From 6a50a9899d806806652f984a5eafd6da38e99db0 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 18 Sep 2022 09:54:17 +0100 Subject: [PATCH 1/7] First implementation ideas --- include/etl/file_error_numbers.h | 1 + include/etl/string_view.h | 8 +- include/etl/to_arithmetic.h | 345 +++++++++++++++++++++++++++++ test/test_string_to_arithmetic.cpp | 68 ++++++ test/vs2019/etl.vcxproj | 2 + test/vs2019/etl.vcxproj.filters | 6 + 6 files changed, 426 insertions(+), 4 deletions(-) create mode 100644 include/etl/to_arithmetic.h create mode 100644 test/test_string_to_arithmetic.cpp diff --git a/include/etl/file_error_numbers.h b/include/etl/file_error_numbers.h index 211c5972..92f67df8 100644 --- a/include/etl/file_error_numbers.h +++ b/include/etl/file_error_numbers.h @@ -98,5 +98,6 @@ SOFTWARE. #define ETL_BIT_STREAM_FILE_ID "65" #define ETL_BYTE_STREAM_FILE_ID "66" #define ETL_BIP_BUFFER_SPSC_ATOMIC_FILE_ID "67" +#define ETL_TO_ARITHMETIC_FILE_ID "68" #endif diff --git a/include/etl/string_view.h b/include/etl/string_view.h index 48bf25ec..bc858dd5 100644 --- a/include/etl/string_view.h +++ b/include/etl/string_view.h @@ -435,7 +435,7 @@ namespace etl ETL_CONSTEXPR14 bool starts_with(etl::basic_string_view view) const { return (size() >= view.size()) && - (compare(0, view.size(), view) == 0); + (compare(0, view.size(), view) == 0); } ETL_CONSTEXPR14 bool starts_with(T c) const @@ -448,7 +448,7 @@ namespace etl size_t lengthtext = TTraits::length(text); return (size() >= lengthtext) && - (compare(0, lengthtext, text) == 0); + (compare(0, lengthtext, text) == 0); } //************************************************************************* @@ -457,7 +457,7 @@ namespace etl ETL_CONSTEXPR14 bool ends_with(etl::basic_string_view view) const { return (size() >= view.size()) && - (compare(size() - view.size(), npos, view) == 0); + (compare(size() - view.size(), npos, view) == 0); } ETL_CONSTEXPR14 bool ends_with(T c) const @@ -471,7 +471,7 @@ namespace etl size_t lengthview = size(); return (lengthview >= lengthtext) && - (compare(lengthview - lengthtext, lengthtext, text) == 0); + (compare(lengthview - lengthtext, lengthtext, text) == 0); } //************************************************************************* diff --git a/include/etl/to_arithmetic.h b/include/etl/to_arithmetic.h new file mode 100644 index 00000000..3aefbe17 --- /dev/null +++ b/include/etl/to_arithmetic.h @@ -0,0 +1,345 @@ + +#include "platform.h" +#include "type_traits.h" +#include "string_view.h" +#include "basic_string.h" +#include "format_spec.h" +#include "radix.h" +#include "optional.h" +#include "string_utilities.h" +#include "iterator.h" +#include "largest.h" +#include "exception.h" +#include "error_handler.h" + +namespace etl +{ + //*************************************************************************** + /// + //*************************************************************************** + class to_arithmetic_exception : public etl::exception + { + public: + + to_arithmetic_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// + //*************************************************************************** + class to_arithmetic_signed_to_unsigned : public to_arithmetic_exception + { + public: + + to_arithmetic_signed_to_unsigned(string_type file_name_, numeric_type line_number_) + : to_arithmetic_exception(ETL_ERROR_TEXT("to arithmetic:signed to unsigned", ETL_TO_ARITHMETIC_FILE_ID"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// + //*************************************************************************** + class to_arithmetic_invalid_format : public to_arithmetic_exception + { + public: + + to_arithmetic_invalid_format(string_type file_name_, numeric_type line_number_) + : to_arithmetic_exception(ETL_ERROR_TEXT("to arithmetic:invalid format", ETL_TO_ARITHMETIC_FILE_ID"B"), file_name_, line_number_) + { + } + }; + + namespace private_to_arithmetic + { + template + struct character_set; + + template <> + struct character_set + { + typedef char value_type; + typedef const value_type* string_type; + static ETL_CONSTANT string_type numeric_chars = "0123456789abcdefABCDEF"; + static ETL_CONSTANT value_type positive_char = '+'; + static ETL_CONSTANT value_type negative_char = '-'; + }; + + template <> + struct character_set + { + typedef wchar_t value_type; + typedef const value_type* string_type; + 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'-'; + }; + + template <> + struct character_set + { + typedef char16_t value_type; + typedef const value_type* string_type; + 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'-'; + }; + + template <> + struct character_set + { + typedef char32_t value_type; + typedef const value_type* string_type; + 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 char binary_length = 2; + static ETL_CONSTANT char octal_length = 8; + static ETL_CONSTANT char decimal_length = 10; + static ETL_CONSTANT char hex_length = 16 + 6; + + //******************************* + template + bool has_valid_characters(etl::basic_string_view view, etl::basic_string_view valid_characters) + { + if (valid_characters.empty()) + { + return false; + } + + size_t position = view.find_first_not_of(valid_characters); + + return position == etl::basic_string_view::npos; + } + + //******************************* + template + char get_digit_value(TChar c) + { + size_t length = etl::strlen(character_set::numeric_chars); + + for (int i = 0; i < length; ++i) + { + if (c == character_set::numeric_chars[i]) + { + return (i < 16) ? i : i - 6; + } + } + + return 0; + } + + //******************************* + template + struct processed_string + { + etl::basic_string_view view; + bool is_negative; + bool is_valid; + }; + + //*************************************************************************** + /// + //*************************************************************************** + template + processed_string preprocess_string(etl::basic_string_view view, const etl::radix::value_type radix) + { + using namespace etl::private_to_arithmetic; + + view = etl::trim_view_whitespace(view); + + const bool has_positive_prefix = (view[0] == character_set::positive_char); + const bool has_negative_prefix = (view[0] == character_set::negative_char); + + // Remove positive or negative prefixes. + if (has_positive_prefix || has_negative_prefix) + { + view.remove_prefix(1); + } + + etl::basic_string_view valid_characters; + + switch (radix) + { + 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: { break; } // No conversion available. + } + + const bool has_valid_prefix = !has_negative_prefix || (radix == etl::radix::decimal); + const bool is_valid = has_valid_prefix && has_valid_characters(view, valid_characters); + + return processed_string{ view, has_negative_prefix, is_valid }; + } + } + + //*************************************************************************** + /// + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type + to_integer(etl::basic_string_view view, const etl::radix::value_type radix) + { + using namespace etl::private_to_arithmetic; + + processed_string data = preprocess_string(view, radix); + + etl::optional result; + + // String input was not in a valid format. + if (!data.is_valid) + { + ETL_ASSERT_FAIL_AND_RETURN_VALUE(ETL_ERROR(etl::to_arithmetic_invalid_format), result); + } + + // Can't convert signed to unsigned. + if (data.is_negative && etl::is_unsigned::value) + { + ETL_ASSERT_FAIL_AND_RETURN_VALUE(ETL_ERROR(etl::to_arithmetic_signed_to_unsigned), result); + } + + if (data.is_valid) + { + T value = 0; + + switch (radix) + { + case etl::radix::decimal: + { + for (etl::basic_string_view::const_iterator itr = data.view.begin(); itr != data.view.end(); ++itr) + { + value *= radix; + + char digit = get_digit_value(*itr); + + data.is_negative ? value -= digit : value += digit; + } + + break; + } + + default: + { + int shift = (radix == etl::radix::binary) ? 1 : (radix == etl::radix::octal) ? 3 : 4; + + for (etl::basic_string_view::const_iterator itr = data.view.begin(); itr != data.view.end(); ++itr) + { + value <<= shift; + + char digit = get_digit_value(*itr); + + value = value | digit; + } + + break; + } + + } + + result = value; + } + + return result; + } + + //*************************************************************************** + /// + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type + to_integer(const etl::basic_string_view& view) + { + return etl::to_integer(view, etl::radix::decimal); + } + + //*************************************************************************** + /// + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type + to_integer(const etl::basic_string_view& view, const etl::basic_format_spec >& spec) + { + return etl::to_integer(view, spec.get_base()); + } + + //*************************************************************************** + /// + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type + to_integer(const TChar* cp, size_t length, const etl::radix::value_type radix) + { + return etl::to_integer(etl::basic_string_view(cp, length), radix); + } + + //*************************************************************************** + /// + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type + to_integer(const TChar* cp, size_t length) + { + return etl::to_integer(etl::basic_string_view(cp, length), etl::radix::decimal);; + } + + //*************************************************************************** + /// + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type + to_integer(const TChar* cp, size_t length, const typename etl::private_basic_format_spec::base_spec& spec) + { + return etl::to_integer(etl::basic_string_view(cp, length), spec.base);; + } + + //*************************************************************************** + /// + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type + to_integer(const etl::ibasic_string& str, const etl::radix::value_type radix) + { + return etl::to_integer(etl::basic_string_view(str), radix);; + } + + //*************************************************************************** + /// + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type + to_integer(const etl::ibasic_string& str) + { + return etl::to_integer(etl::basic_string_view(str), radix);; + } + + //*************************************************************************** + /// + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type + to_integer(const etl::ibasic_string& str, const etl::basic_format_spec >& spec) + { + return etl::to_integer(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_integer(view, radix); + } + + 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); + } +} diff --git a/test/test_string_to_arithmetic.cpp b/test/test_string_to_arithmetic.cpp new file mode 100644 index 00000000..06f5e5a3 --- /dev/null +++ b/test/test_string_to_arithmetic.cpp @@ -0,0 +1,68 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2019 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "unit_test_framework.h" + +#include +#include +#include + +#include "etl/to_arithmetic.h" +#include "etl/string.h" +#include "etl/format_spec.h" + +#undef STR +#define STR(x) x + +namespace +{ + typedef etl::format_spec Format; + + SUITE(test_to_arithmetic) + { + TEST(test_to_integer_from_char_pointer_to_decimals) + { + const char* pp = " -128 "; + const char* pn = " -123"; + + const std::string huge_n("8000000000000001"); + const std::string huge_p("7FFFFFFFFFFFFFFF"); + + //CHECK_EQUAL(int(-128), etl::to_integer(pp, strlen(pp), etl::dec).value()); + + CHECK_EQUAL(std::numeric_limits::min(), etl::to_integer(huge_n.c_str(), huge_n.size(), etl::hex).value()); + CHECK_EQUAL(std::numeric_limits::max(), etl::to_integer(huge_p.c_str(), huge_p.size(), etl::hex).value()); + + //CHECK_EQUAL(123, etl::to_integer(pp, 3, etl::dec)); + //CHECK_EQUAL(123, etl::to_integer(pp, 3, etl::radix::decimal)); + //CHECK_EQUAL(123, etl::to_integer(pp, 3, etl::radix(etl::radix::decimal))); + //CHECK_EQUAL(123, etl::to_integer(pp, 3, 10)); + } + } +} + diff --git a/test/vs2019/etl.vcxproj b/test/vs2019/etl.vcxproj index 9bddcf62..369e134e 100644 --- a/test/vs2019/etl.vcxproj +++ b/test/vs2019/etl.vcxproj @@ -2587,6 +2587,7 @@ + @@ -12106,6 +12107,7 @@ + diff --git a/test/vs2019/etl.vcxproj.filters b/test/vs2019/etl.vcxproj.filters index d0d1c4f6..bc2ee0d7 100644 --- a/test/vs2019/etl.vcxproj.filters +++ b/test/vs2019/etl.vcxproj.filters @@ -1335,6 +1335,9 @@ ETL\Utilities + + ETL\Strings + @@ -3368,6 +3371,9 @@ Tests\Binary + + Tests\Strings + From fe6e0095b32a7b90cbcff5719222baab9b6f3e50 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Mon, 19 Sep 2022 18:50:17 +0100 Subject: [PATCH 2/7] Refactored to_arithmetic --- include/etl/to_arithmetic.h | 230 ++++++++++++++--------------- test/test_string_to_arithmetic.cpp | 208 ++++++++++++++++++++++++-- 2 files changed, 308 insertions(+), 130 deletions(-) diff --git a/include/etl/to_arithmetic.h b/include/etl/to_arithmetic.h index 3aefbe17..4c9a75bc 100644 --- a/include/etl/to_arithmetic.h +++ b/include/etl/to_arithmetic.h @@ -53,6 +53,19 @@ namespace etl } }; + //*************************************************************************** + /// + //*************************************************************************** + class to_arithmetic_radix_not_supported : public to_arithmetic_exception + { + public: + + to_arithmetic_radix_not_supported(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_) + { + } + }; + namespace private_to_arithmetic { template @@ -103,20 +116,6 @@ namespace etl static ETL_CONSTANT char decimal_length = 10; static ETL_CONSTANT char hex_length = 16 + 6; - //******************************* - template - bool has_valid_characters(etl::basic_string_view view, etl::basic_string_view valid_characters) - { - if (valid_characters.empty()) - { - return false; - } - - size_t position = view.find_first_not_of(valid_characters); - - return position == etl::basic_string_view::npos; - } - //******************************* template char get_digit_value(TChar c) @@ -134,49 +133,44 @@ namespace etl return 0; } - //******************************* - template - struct processed_string - { - etl::basic_string_view view; - bool is_negative; - bool is_valid; - }; - //*************************************************************************** /// //*************************************************************************** template - processed_string preprocess_string(etl::basic_string_view view, const etl::radix::value_type radix) + ETL_CONSTEXPR14 bool is_valid_numeric_character(const TChar c, + const etl::basic_string_view& valid_characters) { using namespace etl::private_to_arithmetic; - view = etl::trim_view_whitespace(view); + etl::basic_string_view itr = etl::find(valid_characters.begin(), valid_characters.end(), c); - const bool has_positive_prefix = (view[0] == character_set::positive_char); - const bool has_negative_prefix = (view[0] == character_set::negative_char); - - // Remove positive or negative prefixes. - if (has_positive_prefix || has_negative_prefix) - { - view.remove_prefix(1); - } - - etl::basic_string_view valid_characters; + 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) + { switch (radix) { - 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: { break; } // No conversion available. + case etl::radix::decimal: + { + value *= radix; + is_negative ? value -= digit : value += digit; + break; + } + + default: // Binary, octal or hex. + { + value <<= shift; + value = value | digit; + break; + } } - const bool has_valid_prefix = !has_negative_prefix || (radix == etl::radix::decimal); - const bool is_valid = has_valid_prefix && has_valid_characters(view, valid_characters); - - return processed_string{ view, has_negative_prefix, is_valid }; + return value; } } @@ -185,65 +179,72 @@ namespace etl //*************************************************************************** template ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type - to_integer(etl::basic_string_view view, const etl::radix::value_type radix) + to_arithmetic(etl::basic_string_view view, const etl::radix::value_type radix) { using namespace etl::private_to_arithmetic; - processed_string data = preprocess_string(view, radix); - etl::optional result; - // String input was not in a valid format. - if (!data.is_valid) + bool finished_parsing = false; + + etl::basic_string_view valid_characters; + + switch (radix) { - ETL_ASSERT_FAIL_AND_RETURN_VALUE(ETL_ERROR(etl::to_arithmetic_invalid_format), result); + 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; } } - // Can't convert signed to unsigned. - if (data.is_negative && etl::is_unsigned::value) - { - ETL_ASSERT_FAIL_AND_RETURN_VALUE(ETL_ERROR(etl::to_arithmetic_signed_to_unsigned), result); - } - - if (data.is_valid) + if (!finished_parsing) { T value = 0; - switch (radix) + // 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) { - case etl::radix::decimal: - { - for (etl::basic_string_view::const_iterator itr = data.view.begin(); itr != data.view.end(); ++itr) - { - value *= radix; - - char digit = get_digit_value(*itr); - - data.is_negative ? value -= digit : value += digit; - } - - break; - } - - default: - { - int shift = (radix == etl::radix::binary) ? 1 : (radix == etl::radix::octal) ? 3 : 4; - - for (etl::basic_string_view::const_iterator itr = data.view.begin(); itr != data.view.end(); ++itr) - { - value <<= shift; - - char digit = get_digit_value(*itr); - - value = value | digit; - } - - break; - } - + ++itr; } - result = value; + // Negative prefix is only allowed with decimals. + if (has_negative_prefix && (radix != etl::radix::decimal)) + { + 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)) + { + value = accumulate_value(value, get_digit_value(*itr), has_negative_prefix, shift, radix); + + ++itr; + + if (itr == view.end()) + { + result = value; + finished_parsing = true; + } + } + else + { + // Character was not a valid numeric, so fail. + ETL_ASSERT_FAIL(ETL_ERROR(etl::to_arithmetic_invalid_format)); + finished_parsing = true; + } + } } return result; @@ -254,9 +255,9 @@ namespace etl //*************************************************************************** template ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type - to_integer(const etl::basic_string_view& view) + to_arithmetic(const etl::basic_string_view& view) { - return etl::to_integer(view, etl::radix::decimal); + return etl::to_arithmetic(view, etl::radix::decimal); } //*************************************************************************** @@ -264,9 +265,9 @@ namespace etl //*************************************************************************** template ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type - to_integer(const etl::basic_string_view& view, const etl::basic_format_spec >& spec) + to_arithmetic(const etl::basic_string_view& view, const etl::basic_format_spec >& spec) { - return etl::to_integer(view, spec.get_base()); + return etl::to_arithmetic(view, spec.get_base()); } //*************************************************************************** @@ -274,9 +275,9 @@ namespace etl //*************************************************************************** template ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type - to_integer(const TChar* cp, size_t length, const etl::radix::value_type radix) + to_arithmetic(const TChar* cp, size_t length, const etl::radix::value_type radix) { - return etl::to_integer(etl::basic_string_view(cp, length), radix); + return etl::to_arithmetic(etl::basic_string_view(cp, length), radix); } //*************************************************************************** @@ -284,9 +285,9 @@ namespace etl //*************************************************************************** template ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type - to_integer(const TChar* cp, size_t length) + to_arithmetic(const TChar* cp, size_t length) { - return etl::to_integer(etl::basic_string_view(cp, length), etl::radix::decimal);; + return etl::to_arithmetic(etl::basic_string_view(cp, length), etl::radix::decimal);; } //*************************************************************************** @@ -294,9 +295,9 @@ namespace etl //*************************************************************************** template ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type - to_integer(const TChar* cp, size_t length, const typename etl::private_basic_format_spec::base_spec& spec) + to_arithmetic(const TChar* cp, size_t length, const typename etl::private_basic_format_spec::base_spec& spec) { - return etl::to_integer(etl::basic_string_view(cp, length), spec.base);; + return etl::to_arithmetic(etl::basic_string_view(cp, length), spec.base);; } //*************************************************************************** @@ -304,9 +305,9 @@ namespace etl //*************************************************************************** template ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type - to_integer(const etl::ibasic_string& str, const etl::radix::value_type radix) + to_arithmetic(const etl::ibasic_string& str, const etl::radix::value_type radix) { - return etl::to_integer(etl::basic_string_view(str), radix);; + return etl::to_arithmetic(etl::basic_string_view(str), radix);; } //*************************************************************************** @@ -314,9 +315,9 @@ namespace etl //*************************************************************************** template ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type - to_integer(const etl::ibasic_string& str) + to_arithmetic(const etl::ibasic_string& str) { - return etl::to_integer(etl::basic_string_view(str), radix);; + return etl::to_arithmetic(etl::basic_string_view(str), radix);; } //*************************************************************************** @@ -324,22 +325,15 @@ namespace etl //*************************************************************************** template ETL_CONSTEXPR14 typename etl::enable_if::value, etl::optional >::type - to_integer(const etl::ibasic_string& str, const etl::basic_format_spec >& spec) + to_arithmetic(const etl::ibasic_string& str, const etl::basic_format_spec >& spec) { - return etl::to_integer(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_integer(view, radix); - } - - 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); - } + //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); + //} } diff --git a/test/test_string_to_arithmetic.cpp b/test/test_string_to_arithmetic.cpp index 06f5e5a3..8519dfd9 100644 --- a/test/test_string_to_arithmetic.cpp +++ b/test/test_string_to_arithmetic.cpp @@ -45,23 +45,207 @@ namespace SUITE(test_to_arithmetic) { - TEST(test_to_integer_from_char_pointer_to_decimals) + //************************************************************************* + TEST(test_invalid_radixes) { - const char* pp = " -128 "; - const char* pn = " -123"; + 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 huge_n("8000000000000001"); - const std::string huge_p("7FFFFFFFFFFFFFFF"); + //************************************************************************* + TEST(test_invalid_binary_numerics) + { + const char* decimal1 = " 101"; + const char* decimal2 = "101 "; + const char* decimal3 = "121"; + const char* decimal4 = "-101"; - //CHECK_EQUAL(int(-128), etl::to_integer(pp, strlen(pp), etl::dec).value()); + 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_EQUAL(std::numeric_limits::min(), etl::to_integer(huge_n.c_str(), huge_n.size(), etl::hex).value()); - CHECK_EQUAL(std::numeric_limits::max(), etl::to_integer(huge_p.c_str(), huge_p.size(), etl::hex).value()); + //************************************************************************* + TEST(test_valid_binary_numerics) + { + const std::string value1("0"); + const std::string value2("1"); + const std::string value3("0101"); + const std::string value4("1010"); + const std::string value5("01010011"); + const std::string value6("10101100"); - //CHECK_EQUAL(123, etl::to_integer(pp, 3, etl::dec)); - //CHECK_EQUAL(123, etl::to_integer(pp, 3, etl::radix::decimal)); - //CHECK_EQUAL(123, etl::to_integer(pp, 3, etl::radix(etl::radix::decimal))); - //CHECK_EQUAL(123, etl::to_integer(pp, 3, 10)); + 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())); + } + + //************************************************************************* + TEST(test_big_binary_numerics) + { + const std::string value1("1000000000000000000000000000000000000000000000000000000000000000"); + const std::string value2("0111111111111111111111111111111111111111111111111111111111111111"); + const std::string value3("1111111111111111111111111111111111111111111111111111111111111111"); + + CHECK_EQUAL(uint64_t(0x8000000000000000ULL), etl::to_arithmetic(value1.c_str(), value1.size(), etl::bin).value()); + CHECK_EQUAL(uint64_t(0x7FFFFFFFFFFFFFFFULL), etl::to_arithmetic(value2.c_str(), value2.size(), etl::bin).value()); + CHECK_EQUAL(uint64_t(0xFFFFFFFFFFFFFFFFULL), etl::to_arithmetic(value3.c_str(), value3.size(), etl::bin).value()); + } + + //************************************************************************* + TEST(test_invalid_octal_numerics) + { + const char* decimal1 = " 127"; + const char* decimal2 = "127 "; + const char* decimal3 = "187"; + const char* decimal4 = "-127"; + + 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); + } + + //************************************************************************* + TEST(test_valid_octal_numerics) + { + const std::string value1("0"); + const std::string value2("1"); + const std::string value3("5"); + const std::string value4("12"); + const std::string value5("123"); + const std::string value6("254"); + + 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())); + } + + //************************************************************************* + TEST(test_big_octal_numerics) + { + const std::string value1("1000000000000000000000"); + const std::string value2("0777777777777777777777"); + const std::string value3("1777777777777777777777"); + + CHECK_EQUAL(uint64_t(0x8000000000000000ULL), etl::to_arithmetic(value1.c_str(), value1.size(), etl::oct).value()); + CHECK_EQUAL(uint64_t(0x7FFFFFFFFFFFFFFFULL), etl::to_arithmetic(value2.c_str(), value2.size(), etl::oct).value()); + CHECK_EQUAL(uint64_t(0xFFFFFFFFFFFFFFFFULL), etl::to_arithmetic(value3.c_str(), value3.size(), etl::oct).value()); + } + + //************************************************************************* + 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"; + + 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); + } + + //************************************************************************* + 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"); + + 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())); + } + + //************************************************************************* + TEST(test_big_decimal_numerics) + { + const std::string value1("-9223372036854775808"); + const std::string value2("9223372036854775807"); + const std::string value3("-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()); + } + + //************************************************************************* + TEST(test_invalid_hex_numerics) + { + const char* decimal1 = " 1Af"; + const char* decimal2 = "1Af "; + const char* decimal3 = "1Gf"; + const char* decimal4 = "-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); + } + + //************************************************************************* + 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"); + + 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())); + } + + //************************************************************************* + TEST(test_big_hex_numerics) + { + const std::string value1("8000000000000000"); + const std::string value2("7FFFFFFFFFFFFFFF"); + const std::string value3("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()); } } } From b3deaa6761d4e1090f64944ae29e5015974b0815 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 24 Sep 2022 13:12:18 +0100 Subject: [PATCH 3/7] Added etl::npos Added specialisation of etl::optional for POD --- include/etl/integral_limits.h | 2 + include/etl/optional.h | 392 +++++++++++++++++++++++++++++++--- 2 files changed, 360 insertions(+), 34 deletions(-) diff --git a/include/etl/integral_limits.h b/include/etl/integral_limits.h index ab4884ef..a93f6c88 100644 --- a/include/etl/integral_limits.h +++ b/include/etl/integral_limits.h @@ -215,6 +215,8 @@ namespace etl static ETL_CONSTANT int bits = CHAR_BIT * (sizeof(unsigned long long) / sizeof(char)); static ETL_CONSTANT bool is_signed = etl::is_signed::value; }; + + static ETL_CONSTANT size_t npos = etl::integral_limits::max; } #include "private/minmax_pop.h" diff --git a/include/etl/optional.h b/include/etl/optional.h index b4c97792..16574a84 100644 --- a/include/etl/optional.h +++ b/include/etl/optional.h @@ -103,8 +103,14 @@ namespace etl ///\tparam The type to store. ///\ingroup utilities //***************************************************************************** + template ::value> + class optional; + + //***************************************************************************** + /// For non POD types. + //***************************************************************************** template - class optional + class optional { public: @@ -359,7 +365,6 @@ namespace etl return valid; } - //*************************************************************************** /// Get a reference to the value. //*************************************************************************** @@ -507,11 +512,322 @@ namespace etl bool valid; }; + //***************************************************************************** + /// For POD types. + //***************************************************************************** + template + class optional + { + public: + + //*************************************************************************** + /// Constructor. + //*************************************************************************** + ETL_CONSTEXPR14 optional() + : storage() + , valid(false) + { + } + + //*************************************************************************** + /// Constructor with nullopt. + //*************************************************************************** + ETL_CONSTEXPR14 optional(etl::nullopt_t) + : storage() + , valid(false) + { + } + + //*************************************************************************** + /// Copy constructor. + //*************************************************************************** + ETL_CONSTEXPR14 optional(const optional& other) + : valid(bool(other)) + , storage(other.storage) + { + } + +#if ETL_USING_CPP11 + //*************************************************************************** + /// Move constructor. + //*************************************************************************** + ETL_CONSTEXPR14 optional(optional&& other) + : valid(bool(other)) + , storage(etl::move(other.storage)) + { + } +#endif + + //*************************************************************************** + /// Constructor from value type. + //*************************************************************************** + ETL_CONSTEXPR14 optional(const T& value_) + : storage(value_) + , valid(true) + { + } + +#if ETL_USING_CPP11 + //*************************************************************************** + /// Constructor from value type. + //*************************************************************************** + ETL_CONSTEXPR14 optional(T&& value_) + : storage(etl::move(value_)) + , valid(true) + { + } +#endif + + //*************************************************************************** + /// Assignment operator from nullopt. + //*************************************************************************** + ETL_CONSTEXPR14 optional& operator =(etl::nullopt_t) + { + return *this; + } + + //*************************************************************************** + /// Assignment operator from optional. + //*************************************************************************** + ETL_CONSTEXPR14 optional& operator =(const optional& other) + { + if (this != &other) + { + storage = other.storage; + valid = other.valid; + } + + return *this; + } + +#if ETL_USING_CPP11 + //*************************************************************************** + /// Assignment operator from optional. + //*************************************************************************** + ETL_CONSTEXPR14 optional& operator =(optional&& other) + { + if (this != &other) + { + storage = etl::move(other.storage); + valid = true; + } + + return *this; + } +#endif + + //*************************************************************************** + /// Assignment operator from value type. + //*************************************************************************** + ETL_CONSTEXPR14 optional& operator =(const T& value_) + { + storage = value_; + valid = true; + + return *this; + } + +#if ETL_USING_CPP11 + //*************************************************************************** + /// Assignment operator from value type. + //*************************************************************************** + ETL_CONSTEXPR14 optional& operator =(T&& value_) + { + storage = etl::move(value_); + valid = true; + + return *this; + } +#endif + + //*************************************************************************** + /// Pointer operator. + //*************************************************************************** + ETL_CONSTEXPR14 T* operator ->() + { +#if ETL_IS_DEBUG_BUILD + ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); +#endif + + return &storage; + } + + //*************************************************************************** + /// Pointer operator. + //*************************************************************************** + ETL_CONSTEXPR14 const T* operator ->() const + { +#if ETL_IS_DEBUG_BUILD + ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); +#endif + + return &storage; + } + + //*************************************************************************** + /// Dereference operator. + //*************************************************************************** + ETL_CONSTEXPR14 T& operator *() + { +#if ETL_IS_DEBUG_BUILD + ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); +#endif + + return storage; + } + + //*************************************************************************** + /// Dereference operator. + //*************************************************************************** + ETL_CONSTEXPR14 const T& operator *() const + { +#if ETL_IS_DEBUG_BUILD + ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); +#endif + + return storage; + } + + //*************************************************************************** + /// Bool conversion operator. + //*************************************************************************** + ETL_CONSTEXPR14 operator bool() const + { + return valid; + } + + //*************************************************************************** + // Check whether optional contains value + //*************************************************************************** + ETL_CONSTEXPR14 bool has_value() const ETL_NOEXCEPT + { + return valid; + } + + //*************************************************************************** + /// Get a reference to the value. + //*************************************************************************** + ETL_CONSTEXPR14 T& value() + { +#if ETL_IS_DEBUG_BUILD + ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); +#endif + + return storage; + } + + //*************************************************************************** + /// Get a const reference to the value. + //*************************************************************************** + ETL_CONSTEXPR14 const T& value() const + { +#if ETL_IS_DEBUG_BUILD + ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); +#endif + + return storage; + } + + //*************************************************************************** + /// Gets the value or a default if no valid. + //*************************************************************************** + ETL_CONSTEXPR14 T value_or(T default_value) const + { + return valid ? value() : default_value; + } + + //*************************************************************************** + /// Swaps this value with another. + //*************************************************************************** + ETL_CONSTEXPR14 void swap(optional& other) + { + optional temp(*this); + *this = other; + other = temp; + } + + //*************************************************************************** + /// Reset back to invalid. + //*************************************************************************** + ETL_CONSTEXPR14 void reset() + { + valid = false; + } + +#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_OPTIONAL_FORCE_CPP03_IMPLEMENTATION) + //************************************************************************* + /// Emplaces a value. + ///\param args The arguments to construct with. + //************************************************************************* + template + ETL_CONSTEXPR14 void emplace(Args && ... args) + { + if (valid) + { + // Destroy the old one. + storage.template get_reference().~T(); + } + + storage = T(ETL_OR_STD::forward(args)...); + valid = true; + } +#else + //************************************************************************* + /// Emplaces a value. + /// 1 parameter. + //************************************************************************* + template + void emplace(const T1& value1) + { + storage = value1; + valid = true; + } + + //************************************************************************* + /// Emplaces a value. + /// 2 parameters. + //************************************************************************* + template + void emplace(const T1& value1, const T2& value2) + { + storage = T(value1, value2); + valid = true; + } + + //************************************************************************* + /// Emplaces a value. + /// 3 parameters. + //************************************************************************* + template + void emplace(const T1& value1, const T2& value2, const T3& value3) + { + storage = T(value1, value2, value3); + valid = true; + } + + //************************************************************************* + /// Emplaces a value. + /// 4 parameters. + //************************************************************************* + template + void emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { + storage = T(value1, value2, value3, value4); + valid = true; + } +#endif + + private: + + T storage; + bool valid; + }; + //*************************************************************************** /// Equality operator. cppreference 1 //*************************************************************************** template - bool operator ==(const etl::optional& lhs, const etl::optional& rhs) + ETL_CONSTEXPR14 bool operator ==(const etl::optional& lhs, const etl::optional& rhs) { if (bool(lhs) != bool(rhs)) { @@ -531,7 +847,7 @@ namespace etl /// Equality operator. cppreference 2 //*************************************************************************** template - bool operator !=(const etl::optional& lhs, const etl::optional& rhs) + ETL_CONSTEXPR14 bool operator !=(const etl::optional& lhs, const etl::optional& rhs) { return !(lhs == rhs); } @@ -540,7 +856,7 @@ namespace etl /// Less than operator. cppreference 3 //*************************************************************************** template - bool operator <(const etl::optional& lhs, const etl::optional& rhs) + ETL_CONSTEXPR14 bool operator <(const etl::optional& lhs, const etl::optional& rhs) { if (!bool(rhs)) { @@ -560,7 +876,7 @@ namespace etl /// Less than equal operator. cppreference 4 //*************************************************************************** template - bool operator <=(const etl::optional& lhs, const etl::optional& rhs) + ETL_CONSTEXPR14 bool operator <=(const etl::optional& lhs, const etl::optional& rhs) { if (!bool(lhs)) { @@ -580,7 +896,7 @@ namespace etl /// greater than operator. cppreference 5 //*************************************************************************** template - bool operator >(const etl::optional& lhs, const etl::optional& rhs) + ETL_CONSTEXPR14 bool operator >(const etl::optional& lhs, const etl::optional& rhs) { if (!bool(lhs)) { @@ -600,7 +916,7 @@ namespace etl /// greater than equal operator. cppreference 6 //*************************************************************************** template - bool operator >=(const etl::optional& lhs, const etl::optional& rhs) + ETL_CONSTEXPR14 bool operator >=(const etl::optional& lhs, const etl::optional& rhs) { if (!bool(rhs)) { @@ -620,7 +936,7 @@ namespace etl /// Equality operator. cppreference 7 //*************************************************************************** template - bool operator ==(const etl::optional& lhs, etl::nullopt_t) + ETL_CONSTEXPR14 bool operator ==(const etl::optional& lhs, etl::nullopt_t) { return !bool(lhs); } @@ -629,7 +945,7 @@ namespace etl /// Equality operator. cppreference 8 //*************************************************************************** template - bool operator ==(etl::nullopt_t, const etl::optional& rhs) + ETL_CONSTEXPR14 bool operator ==(etl::nullopt_t, const etl::optional& rhs) { return !bool(rhs); } @@ -638,7 +954,7 @@ namespace etl /// Inequality operator. cppreference 9 //*************************************************************************** template - bool operator !=(const etl::optional& lhs, etl::nullopt_t) + ETL_CONSTEXPR14 bool operator !=(const etl::optional& lhs, etl::nullopt_t) { return !(lhs == etl::nullopt); } @@ -647,7 +963,7 @@ namespace etl /// Inequality operator. cppreference 10 //*************************************************************************** template - bool operator !=(etl::nullopt_t , const etl::optional& rhs) + ETL_CONSTEXPR14 bool operator !=(etl::nullopt_t , const etl::optional& rhs) { return !(etl::nullopt == rhs); } @@ -656,7 +972,7 @@ namespace etl /// Less than operator. cppreference 11 //*************************************************************************** template - bool operator <(const etl::optional&, etl::nullopt_t) + ETL_CONSTEXPR14 bool operator <(const etl::optional&, etl::nullopt_t) { return false; } @@ -665,7 +981,7 @@ namespace etl /// Less than operator. cppreference 12 //*************************************************************************** template - bool operator <(etl::nullopt_t, const etl::optional& rhs) + ETL_CONSTEXPR14 bool operator <(etl::nullopt_t, const etl::optional& rhs) { return bool(rhs); } @@ -674,7 +990,7 @@ namespace etl /// Less than equal operator. cppreference 13 //*************************************************************************** template - bool operator <=(const etl::optional& lhs, etl::nullopt_t) + ETL_CONSTEXPR14 bool operator <=(const etl::optional& lhs, etl::nullopt_t) { return !bool(lhs); } @@ -683,7 +999,7 @@ namespace etl /// Less than equal operator. cppreference 14 //*************************************************************************** template - bool operator <=(etl::nullopt_t, const etl::optional&) + ETL_CONSTEXPR14 bool operator <=(etl::nullopt_t, const etl::optional&) { return true; } @@ -692,7 +1008,7 @@ namespace etl /// Greater than operator. cppreference 15 //*************************************************************************** template - bool operator >(const etl::optional& lhs, etl::nullopt_t) + ETL_CONSTEXPR14 bool operator >(const etl::optional& lhs, etl::nullopt_t) { return bool(lhs); } @@ -701,7 +1017,7 @@ namespace etl /// Greater than operator. cppreference 16 //*************************************************************************** template - bool operator >(etl::nullopt_t, const etl::optional&) + ETL_CONSTEXPR14 bool operator >(etl::nullopt_t, const etl::optional&) { return false; } @@ -710,7 +1026,7 @@ namespace etl /// Greater than equal operator. cppreference 17 //*************************************************************************** template - bool operator >=(const etl::optional&, etl::nullopt_t) + ETL_CONSTEXPR14 bool operator >=(const etl::optional&, etl::nullopt_t) { return true; } @@ -719,7 +1035,7 @@ namespace etl /// Greater than equal operator. cppreference 18 //*************************************************************************** template - bool operator >=(etl::nullopt_t, const etl::optional& rhs) + ETL_CONSTEXPR14 bool operator >=(etl::nullopt_t, const etl::optional& rhs) { return !bool(rhs); } @@ -728,7 +1044,7 @@ namespace etl /// Equality operator. cppreference 19 //************************************************************************** template - bool operator ==(const etl::optional& lhs, const U& rhs) + ETL_CONSTEXPR14 bool operator ==(const etl::optional& lhs, const U& rhs) { return bool(lhs) ? lhs.value() == rhs : false; } @@ -737,7 +1053,7 @@ namespace etl /// Inequality operator. cppreference 21 //************************************************************************** template - bool operator !=(const etl::optional& lhs, const U& rhs) + ETL_CONSTEXPR14 bool operator !=(const etl::optional& lhs, const U& rhs) { return !(lhs == rhs); } @@ -746,7 +1062,7 @@ namespace etl /// Equality operator. cppreference 20 //************************************************************************** template - bool operator ==(const U& lhs, const etl::optional& rhs) + ETL_CONSTEXPR14 bool operator ==(const U& lhs, const etl::optional& rhs) { return bool(rhs) ? rhs.value() == lhs : false; } @@ -755,7 +1071,7 @@ namespace etl /// Inequality operator. cppreference 22 //************************************************************************** template - bool operator !=(const U& lhs, const etl::optional& rhs) + ETL_CONSTEXPR14 bool operator !=(const U& lhs, const etl::optional& rhs) { return !(lhs == rhs); } @@ -764,7 +1080,7 @@ namespace etl /// Less than operator. cppreference 23 //*************************************************************************** template - bool operator <(const etl::optional& lhs, const U& rhs) + ETL_CONSTEXPR14 bool operator <(const etl::optional& lhs, const U& rhs) { return bool(lhs) ? lhs.value() < rhs : true; } @@ -773,7 +1089,7 @@ namespace etl /// Less than operator. cppreference 24 //*************************************************************************** template - bool operator <(const U& lhs, const etl::optional& rhs) + ETL_CONSTEXPR14 bool operator <(const U& lhs, const etl::optional& rhs) { return bool(rhs) ? lhs < rhs.value() : false; } @@ -782,7 +1098,7 @@ namespace etl /// Less than equal operator. cppreference 25 //*************************************************************************** template - bool operator <=(const etl::optional& lhs, const U& rhs) + ETL_CONSTEXPR14 bool operator <=(const etl::optional& lhs, const U& rhs) { return bool(lhs) ? lhs.value() <= rhs : true; } @@ -791,7 +1107,7 @@ namespace etl /// Less than equal operator. cppreference 26 //*************************************************************************** template - bool operator <=(const U& lhs, const etl::optional& rhs) + ETL_CONSTEXPR14 bool operator <=(const U& lhs, const etl::optional& rhs) { return bool(rhs) ? lhs <= rhs.value() : false; } @@ -800,7 +1116,7 @@ namespace etl /// Greater than operator. cppreference 27 //*************************************************************************** template - bool operator >(const etl::optional& lhs, const U& rhs) + ETL_CONSTEXPR14 bool operator >(const etl::optional& lhs, const U& rhs) { return bool(lhs) ? lhs.value() > rhs : false; } @@ -809,7 +1125,7 @@ namespace etl /// Greater than operator. cppreference 28 //*************************************************************************** template - bool operator >(const U& lhs, const etl::optional& rhs) + ETL_CONSTEXPR14 bool operator >(const U& lhs, const etl::optional& rhs) { return bool(rhs) ? lhs > rhs.value() : true; } @@ -818,7 +1134,7 @@ namespace etl /// Greater than equal operator. cppreference 29 //*************************************************************************** template - bool operator >=(const etl::optional& lhs, const U& rhs) + ETL_CONSTEXPR14 bool operator >=(const etl::optional& lhs, const U& rhs) { return bool(lhs) ? lhs.value() >= rhs : false; } @@ -827,7 +1143,7 @@ namespace etl /// Greater than equal operator. cppreference 30 //*************************************************************************** template - bool operator >=(const U& lhs, const etl::optional& rhs) + ETL_CONSTEXPR14 bool operator >=(const U& lhs, const etl::optional& rhs) { return bool(rhs) ? lhs >= rhs.value() : true; } @@ -836,17 +1152,25 @@ namespace etl /// Make an optional. //*************************************************************************** template - etl::optional::type> make_optional(T& value) + ETL_CONSTEXPR14 etl::optional::type> make_optional(T& value) { return etl::optional::type>(value); } + + //*************************************************************************** + /// Template deduction guides. + //*************************************************************************** +#if ETL_CPP17_SUPPORTED + template + etl::optional(T) -> etl::optional; +#endif } //************************************************************************* /// Swaps the values. //************************************************************************* template -void swap(etl::optional& lhs, etl::optional& rhs) +ETL_CONSTEXPR14 void swap(etl::optional& lhs, etl::optional& rhs) { lhs.swap(rhs); } From b5f6227870c6c9de8224b46fbc6916aeaf8db096 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 24 Sep 2022 13:13:06 +0100 Subject: [PATCH 4/7] 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); } } } From 139c564ff2aa6019fa8775bc69f30835bb704a82 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 24 Sep 2022 20:28:35 +0100 Subject: [PATCH 5/7] Experimental algorithm --- include/etl/to_arithmetic.h | 282 +++++++++++++++++++++++------------- 1 file changed, 180 insertions(+), 102 deletions(-) diff --git a/include/etl/to_arithmetic.h b/include/etl/to_arithmetic.h index 97fb6e2a..82933d42 100644 --- a/include/etl/to_arithmetic.h +++ b/include/etl/to_arithmetic.h @@ -68,128 +68,182 @@ namespace etl namespace private_to_arithmetic { + static ETL_CONSTANT char binary_length = 2; + static ETL_CONSTANT char octal_length = 8; + static ETL_CONSTANT char decimal_length = 10; + static ETL_CONSTANT char hex_length = 16; + static ETL_CONSTANT int valid_length = 28; + //*********************************************************************** /// //*********************************************************************** + struct valid_character_set + { + typedef char value_type; + typedef const value_type* string_type; + static ETL_CONSTANT string_type valid_chars = "+-.,eE0123456789abcdefABCDEF"; + static ETL_CONSTANT string_type numeric_chars = "0123456789abcdef"; + static ETL_CONSTANT value_type positive_char = '+'; + static ETL_CONSTANT value_type negative_char = '-'; + static ETL_CONSTANT value_type radix_point1 = '.'; + static ETL_CONSTANT value_type radix_point2 = ','; + static ETL_CONSTANT value_type exponential = 'e'; + static ETL_CONSTANT value_type unknown_char = '?'; + + //******************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + bool is_valid(char c, etl::radix::value_type radix) + { + const string_type itr_begin = numeric_chars; + const string_type itr_end = numeric_chars + get_length(radix); + + string_type itr = etl::find(itr_begin, itr_end, c); + + return (itr != itr_end); + } + + //******************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + char digit_value(char c, etl::radix::value_type radix) + { + switch (radix) + { + case etl::radix::binary: + case etl::radix::octal: + case etl::radix::decimal: + { + return c - '0'; + break; + } + + case etl::radix::hex: + { + for (int i = 0; i < 16; ++i) + { + if (c == numeric_chars[i]) + { + return i; + } + } + } + + default: + { + return 0; + break; + } + } + } + + private: + + //******************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + int get_length(etl::radix::value_type radix) + { + switch (radix) + { + case etl::radix::binary: { return binary_length; break; } + case etl::radix::octal: { return octal_length; break; } + case etl::radix::decimal: { return decimal_length; break; } + case etl::radix::hex: { return hex_length; break; } + default: { return 0; break; } + } + } + }; + + //*********************************************************************** + /// The character sets for character types. + //*********************************************************************** template struct character_set; + //******************************************* template <> struct character_set { - typedef char value_type; - typedef const value_type* string_type; - 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"; + ETL_NODISCARD + ETL_CONSTEXPR14 + char lookup(char c) + { + return c; + } }; + //******************************************* template <> struct character_set { typedef wchar_t value_type; typedef const value_type* string_type; - 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"; + static ETL_CONSTANT string_type valid_chars = L"+-.,eE0123456789abcdefABCDEF"; + + ETL_NODISCARD + ETL_CONSTEXPR14 + char lookup(wchar_t c) + { + for (int i = 0; i < valid_length; ++i) + { + if (c == valid_chars[i]) + { + return tolower(valid_character_set::valid_chars[i]); + } + } + + return valid_character_set::unknown_char; + } }; + //******************************************* template <> struct character_set { typedef char16_t value_type; typedef const value_type* string_type; - 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 string_type valid_chars = u"+-.,eE0123456789abcdefABCDEF"; + + ETL_NODISCARD + ETL_CONSTEXPR14 + char lookup(wchar_t c) + { + for (int i = 0; i < valid_length; ++i) + { + if (c == valid_chars[i]) + { + return tolower(valid_character_set::valid_chars[i]); + } + } + + return valid_character_set::unknown_char; + } }; + //******************************************* template <> struct character_set { typedef char32_t value_type; typedef const value_type* string_type; - 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 string_type valid_chars = U"+-.,eE0123456789abcdefABCDEF"; - static ETL_CONSTANT char binary_length = 2; - static ETL_CONSTANT char octal_length = 8; - 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); - - for (int i = 0; i < length; ++i) + ETL_NODISCARD + ETL_CONSTEXPR14 + char lookup(wchar_t c) { - if (c == character_set::numeric_chars[i]) + for (int i = 0; i < valid_length; ++i) { - return (i < 16) ? i : i - 6; + if (c == valid_chars[i]) + { + return tolower(valid_character_set::valid_chars[i]); + } } + + return valid_character_set::unknown_char; } - - return 0; - } - - //*************************************************************************** - /// - //*************************************************************************** - template - ETL_NODISCARD - ETL_CONSTEXPR14 - etl::basic_string_view get_character_set(const etl::radix::value_type radix) - { - 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_NODISCARD - ETL_CONSTEXPR14 - bool is_valid_decimal_character(const TChar c) - { - return (c >= character_set::numeric_chars[0]) && (c <= character_set::numeric_chars[9]); - } + }; //*************************************************************************** /// @@ -326,6 +380,39 @@ namespace etl return value; } + + template + struct to_integral_implementation + { + ETL_NODISCARD + ETL_CONSTEXPR14 + to_integral_implementation(const numeric_information& info_) + : info(info_) + , count(0) + , value(0) + , is_negative(false) + { + } + + ETL_NODISCARD + ETL_CONSTEXPR14 + bool add(char c) + { + if (valid_character_set::is_valid(c)) + { + value = accumulate_value(value, info) + return true; + } + else + { + return false; + } + } + + const numeric_information& info; + int count; + TValue value; + }; } //*************************************************************************** @@ -340,10 +427,11 @@ namespace etl using namespace etl::private_to_arithmetic; etl::optional result; - etl::basic_string_view valid_characters; 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) @@ -363,23 +451,13 @@ namespace etl while (parsing) { - if (is_valid_numeric_character(*itr, view_info.valid_characters)) - { - numeric_info.digit = get_digit_value(*itr); - value = accumulate_value(value, numeric_info); + implementation.add(character_set::lookup(*itr)); - ++itr; + ++itr; - if (itr == view.end()) - { - result = value; - parsing = false; - } - } - else + if (itr == view.end()) { - // Character was not a valid numeric, so fail. - ETL_ASSERT_FAIL(ETL_ERROR(etl::to_arithmetic_invalid_format)); + result = implementation.value; parsing = false; } } From 935425fc4aeb21d2324e024e518eae82337d2b94 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 25 Sep 2022 08:21:47 +0100 Subject: [PATCH 6/7] Work-In-Progress Alternate decoding --- include/etl/to_arithmetic.h | 374 +++++++++++++++++++---------- test/test_string_to_arithmetic.cpp | 50 ++-- 2 files changed, 268 insertions(+), 156 deletions(-) diff --git a/include/etl/to_arithmetic.h b/include/etl/to_arithmetic.h index 82933d42..3db402db 100644 --- a/include/etl/to_arithmetic.h +++ b/include/etl/to_arithmetic.h @@ -93,7 +93,7 @@ namespace etl //******************************************* ETL_NODISCARD ETL_CONSTEXPR14 - bool is_valid(char c, etl::radix::value_type radix) + static bool is_valid(char c, etl::radix::value_type radix) { const string_type itr_begin = numeric_chars; const string_type itr_end = numeric_chars + get_length(radix); @@ -106,7 +106,7 @@ namespace etl //******************************************* ETL_NODISCARD ETL_CONSTEXPR14 - char digit_value(char c, etl::radix::value_type radix) + static char digit_value(char c, etl::radix::value_type radix) { switch (radix) { @@ -127,6 +127,9 @@ namespace etl return i; } } + + return 0; + break; } default: @@ -142,15 +145,15 @@ namespace etl //******************************************* ETL_NODISCARD ETL_CONSTEXPR14 - int get_length(etl::radix::value_type radix) + static int get_length(etl::radix::value_type radix) { switch (radix) { - case etl::radix::binary: { return binary_length; break; } - case etl::radix::octal: { return octal_length; break; } - case etl::radix::decimal: { return decimal_length; break; } - case etl::radix::hex: { return hex_length; break; } - default: { return 0; break; } + case etl::radix::binary: { return binary_length; } + case etl::radix::octal: { return octal_length; } + case etl::radix::decimal: { return decimal_length; } + case etl::radix::hex: { return hex_length; } + default: { ETL_ASSERT_FAIL_AND_RETURN_VALUE(ETL_ERROR(etl::to_arithmetic_invalid_radix), 0) } } } }; @@ -167,7 +170,7 @@ namespace etl { ETL_NODISCARD ETL_CONSTEXPR14 - char lookup(char c) + static char lookup(char c) { return c; } @@ -183,7 +186,7 @@ namespace etl ETL_NODISCARD ETL_CONSTEXPR14 - char lookup(wchar_t c) + static char lookup(wchar_t c) { for (int i = 0; i < valid_length; ++i) { @@ -207,7 +210,7 @@ namespace etl ETL_NODISCARD ETL_CONSTEXPR14 - char lookup(wchar_t c) + static char lookup(wchar_t c) { for (int i = 0; i < valid_length; ++i) { @@ -231,7 +234,7 @@ namespace etl ETL_NODISCARD ETL_CONSTEXPR14 - char lookup(wchar_t c) + static char lookup(wchar_t c) { for (int i = 0; i < valid_length; ++i) { @@ -248,77 +251,77 @@ namespace etl //*************************************************************************** /// //*************************************************************************** - template - struct view_information - { - ETL_CONSTEXPR14 - view_information() - : valid_characters() - { - } + //template + //struct view_information + //{ + // ETL_CONSTEXPR14 + // view_information() + // : valid_characters() + // { + // } - etl::basic_string_view 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; - }; + //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); + //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(); + // 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 (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 (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); + // 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); - } + // // 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)); + // ETL_ASSERT(is_valid, ETL_ERROR(etl::to_arithmetic_invalid_format)); - return is_valid; - } + // return is_valid; + //} //*************************************************************************** /// @@ -327,10 +330,10 @@ namespace etl ETL_NODISCARD ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_unsigned::value, TValue>::type - accumulate_value(TValue value, const numeric_information& info) + accumulate_value(TValue value, char digit, etl::radix::value_type radix, bool is_negative) { - value *= info.radix; - value += info.digit; + value *= radix; + value += digit; return value; } @@ -342,10 +345,10 @@ namespace etl ETL_NODISCARD ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_signed::value, TValue>::type - accumulate_value(TValue value, const numeric_information& info) + accumulate_value(TValue value, char digit, etl::radix::value_type radix, bool is_negative) { - value *= info.radix; - info.is_negative ? value -= info.digit : value += info.digit; + value *= radix; + is_negative ? value -= digit : value += digit; return value; } @@ -353,71 +356,181 @@ namespace etl //*************************************************************************** /// //*************************************************************************** - 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 + //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; - } + // 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; + //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 value; + //} + //*************************************************************************** + /// + //*************************************************************************** template struct to_integral_implementation { + //********************************* ETL_NODISCARD ETL_CONSTEXPR14 - to_integral_implementation(const numeric_information& info_) - : info(info_) - , count(0) + to_integral_implementation(etl::radix::value_type radix_) + : count(0) , value(0) , is_negative(false) + , radix(radix_) { } + //********************************* ETL_NODISCARD ETL_CONSTEXPR14 bool add(char c) { - if (valid_character_set::is_valid(c)) + bool is_valid = true; + + switch (count) { - value = accumulate_value(value, info) - return true; - } - else - { - return false; + 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); + + if (is_valid) + { + value = accumulate_value(value, valid_character_set::digit_value(c, radix), radix, is_negative); + } + } + 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); + } + break; + } } + + ++count; + + return is_valid; } - const numeric_information& info; + //********************************* + bool has_value() const + { + return !(count == 1)/* && */; + } + + //********************************* + TValue get_value() const + { + return value; + } + + private: + int count; TValue value; + bool is_negative; + etl::radix::value_type radix; }; } //*************************************************************************** /// 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. + //*************************************************************************** template ETL_NODISCARD ETL_CONSTEXPR14 @@ -426,43 +539,42 @@ namespace etl { 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) + etl::optional result; + + if (!view.empty()) { - if (etl::is_unsigned::value && numeric_info.is_negative) + to_integral_implementation implementation(radix); + + etl::basic_string_view::const_iterator itr = view.begin(); + + bool parsing = true; + + while (parsing) { - parsing = false; - ETL_ASSERT_FAIL(ETL_ERROR(etl::to_arithmetic_signed_to_unsigned)); - } + parsing = implementation.add(character_set::lookup(*itr)); - if (parsing) - { - // Parse the numeric part. - TValue value = 0; - - etl::basic_string_view::const_iterator itr = view.begin(); - - while (parsing) + if (parsing) { - implementation.add(character_set::lookup(*itr)); - ++itr; if (itr == view.end()) { - result = implementation.value; + 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; } diff --git a/test/test_string_to_arithmetic.cpp b/test/test_string_to_arithmetic.cpp index e5b2d383..8d5b0ac7 100644 --- a/test/test_string_to_arithmetic.cpp +++ b/test/test_string_to_arithmetic.cpp @@ -262,43 +262,43 @@ namespace } //************************************************************************* - TEST(test_valid_float) - { - const std::string text1("-123.456789"); + //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(); + // float f1 = strtof(text1.c_str(), nullptr); + // float f2 = etl::to_arithmetic(text1.c_str(), text1.size()).value(); - CHECK_EQUAL(f1, f2); + // CHECK_EQUAL(f1, f2); - const std::string text2("-1.23456789e2"); - float f3 = etl::to_arithmetic(text2.c_str(), text2.size()).value(); + // const std::string text2("-1.23456789e2"); + // float f3 = etl::to_arithmetic(text2.c_str(), text2.size()).value(); - CHECK_EQUAL(f1, f3); - } + // CHECK_EQUAL(f1, f3); + //} //************************************************************************* - TEST(test_valid_double) - { - const std::string text1("-123.45678901234567"); + //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(); + // double f1 = strtod(text1.c_str(), nullptr); + // double f2 = etl::to_arithmetic(text1.c_str(), text1.size()).value(); - CHECK_EQUAL(f1, f2); - } + // CHECK_EQUAL(f1, f2); + //} //************************************************************************* - TEST(test_constexpr_integral) - { - constexpr const char* text{ "123" }; - constexpr etl::string_view view(text, 3); + //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(); + // constexpr etl::optional opt = etl::to_arithmetic(view, etl::radix::decimal); + // constexpr int i = opt.value(); - CHECK_EQUAL(123, i); - } + // CHECK_EQUAL(123, i); + //} //************************************************************************* TEST(test_constexpr_floating_point) From 68b395b5f98fcc1d739738bc7719a145bc897edc Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 25 Sep 2022 09:21:54 +0100 Subject: [PATCH 7/7] Work-In-Progress Alternate decoding --- include/etl/to_arithmetic.h | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/include/etl/to_arithmetic.h b/include/etl/to_arithmetic.h index 3db402db..28ee76da 100644 --- a/include/etl/to_arithmetic.h +++ b/include/etl/to_arithmetic.h @@ -158,6 +158,19 @@ namespace etl } }; + //******************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + char to_lower(char c) + { + if ((c >= 'A') && (c <= 'Z')) + { + c += 32; + } + + return c; + } + //*********************************************************************** /// The character sets for character types. //*********************************************************************** @@ -172,7 +185,7 @@ namespace etl ETL_CONSTEXPR14 static char lookup(char c) { - return c; + return to_lower(c); } }; @@ -192,7 +205,7 @@ namespace etl { if (c == valid_chars[i]) { - return tolower(valid_character_set::valid_chars[i]); + return to_lower(valid_character_set::valid_chars[i]); } } @@ -216,7 +229,7 @@ namespace etl { if (c == valid_chars[i]) { - return tolower(valid_character_set::valid_chars[i]); + return to_lower(valid_character_set::valid_chars[i]); } } @@ -240,7 +253,7 @@ namespace etl { if (c == valid_chars[i]) { - return tolower(valid_character_set::valid_chars[i]); + return to_lower(valid_character_set::valid_chars[i]); } } @@ -397,6 +410,7 @@ namespace etl : count(0) , value(0) , is_negative(false) + , valid_value(false) , radix(radix_) { } @@ -433,6 +447,7 @@ namespace etl if (is_valid) { value = accumulate_value(value, valid_character_set::digit_value(c, radix), radix, is_negative); + valid_value = true; } } break; @@ -445,6 +460,7 @@ namespace etl if (is_valid) { value = accumulate_value(value, valid_character_set::digit_value(c, radix), radix, is_negative); + valid_value = true; } break; } @@ -458,7 +474,7 @@ namespace etl //********************************* bool has_value() const { - return !(count == 1)/* && */; + return (valid_value == true); } //********************************* @@ -472,6 +488,7 @@ namespace etl int count; TValue value; bool is_negative; + bool valid_value; etl::radix::value_type radix; }; }