Work-In-Progress

Alternate decoding
This commit is contained in:
John Wellbelove 2022-09-25 08:21:47 +01:00
parent d9686c7824
commit 016ebc92d2
2 changed files with 268 additions and 156 deletions

View File

@ -93,7 +93,7 @@ namespace etl
//******************************************* //*******************************************
ETL_NODISCARD ETL_NODISCARD
ETL_CONSTEXPR14 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_begin = numeric_chars;
const string_type itr_end = numeric_chars + get_length(radix); const string_type itr_end = numeric_chars + get_length(radix);
@ -106,7 +106,7 @@ namespace etl
//******************************************* //*******************************************
ETL_NODISCARD ETL_NODISCARD
ETL_CONSTEXPR14 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) switch (radix)
{ {
@ -127,6 +127,9 @@ namespace etl
return i; return i;
} }
} }
return 0;
break;
} }
default: default:
@ -142,15 +145,15 @@ namespace etl
//******************************************* //*******************************************
ETL_NODISCARD ETL_NODISCARD
ETL_CONSTEXPR14 ETL_CONSTEXPR14
int get_length(etl::radix::value_type radix) static int get_length(etl::radix::value_type radix)
{ {
switch (radix) switch (radix)
{ {
case etl::radix::binary: { return binary_length; break; } case etl::radix::binary: { return binary_length; }
case etl::radix::octal: { return octal_length; break; } case etl::radix::octal: { return octal_length; }
case etl::radix::decimal: { return decimal_length; break; } case etl::radix::decimal: { return decimal_length; }
case etl::radix::hex: { return hex_length; break; } case etl::radix::hex: { return hex_length; }
default: { return 0; break; } default: { ETL_ASSERT_FAIL_AND_RETURN_VALUE(ETL_ERROR(etl::to_arithmetic_invalid_radix), 0) }
} }
} }
}; };
@ -167,7 +170,7 @@ namespace etl
{ {
ETL_NODISCARD ETL_NODISCARD
ETL_CONSTEXPR14 ETL_CONSTEXPR14
char lookup(char c) static char lookup(char c)
{ {
return c; return c;
} }
@ -183,7 +186,7 @@ namespace etl
ETL_NODISCARD ETL_NODISCARD
ETL_CONSTEXPR14 ETL_CONSTEXPR14
char lookup(wchar_t c) static char lookup(wchar_t c)
{ {
for (int i = 0; i < valid_length; ++i) for (int i = 0; i < valid_length; ++i)
{ {
@ -207,7 +210,7 @@ namespace etl
ETL_NODISCARD ETL_NODISCARD
ETL_CONSTEXPR14 ETL_CONSTEXPR14
char lookup(wchar_t c) static char lookup(wchar_t c)
{ {
for (int i = 0; i < valid_length; ++i) for (int i = 0; i < valid_length; ++i)
{ {
@ -231,7 +234,7 @@ namespace etl
ETL_NODISCARD ETL_NODISCARD
ETL_CONSTEXPR14 ETL_CONSTEXPR14
char lookup(wchar_t c) static char lookup(wchar_t c)
{ {
for (int i = 0; i < valid_length; ++i) for (int i = 0; i < valid_length; ++i)
{ {
@ -248,77 +251,77 @@ namespace etl
//*************************************************************************** //***************************************************************************
/// ///
//*************************************************************************** //***************************************************************************
template <typename TChar> //template <typename TChar>
struct view_information //struct view_information
{ //{
ETL_CONSTEXPR14 // ETL_CONSTEXPR14
view_information() // view_information()
: valid_characters() // : valid_characters()
{ // {
} // }
etl::basic_string_view<TChar> valid_characters; // etl::basic_string_view<TChar> valid_characters;
}; //};
//********************************* //*********************************
struct numeric_information //struct numeric_information
{ //{
ETL_CONSTEXPR14 // ETL_CONSTEXPR14
numeric_information() // numeric_information()
: digit(0) // : digit(0)
, is_negative(false) // , is_negative(false)
, radix(0) // , radix(0)
, radix_point_position(etl::npos) // , radix_point_position(etl::npos)
, exponential_position(etl::npos) // , exponential_position(etl::npos)
{ // {
} // }
//
char digit; // char digit;
bool is_negative; // bool is_negative;
etl::radix::value_type radix; // etl::radix::value_type radix;
size_t radix_point_position; // size_t radix_point_position;
size_t exponential_position; // size_t exponential_position;
}; //};
//*************************************************************************** //***************************************************************************
/// ///
//*************************************************************************** //***************************************************************************
template <typename TChar> //template <typename TChar>
ETL_NODISCARD //ETL_NODISCARD
ETL_CONSTEXPR14 //ETL_CONSTEXPR14
bool validate_information_from_view(etl::basic_string_view<TChar>& view, etl::radix::value_type radix, view_information<TChar>& view_info, numeric_information& numeric_info) //bool validate_information_from_view(etl::basic_string_view<TChar>& view, etl::radix::value_type radix, view_information<TChar>& view_info, numeric_information& numeric_info)
{ //{
numeric_info.radix = radix; // numeric_info.radix = radix;
view_info.valid_characters = get_character_set<TChar>(numeric_info.radix); // view_info.valid_characters = get_character_set<TChar>(numeric_info.radix);
bool is_valid = !view_info.valid_characters.empty(); // bool is_valid = !view_info.valid_characters.empty();
if (is_valid) // if (is_valid)
{ // {
// Look for a prefix. // // Look for a prefix.
const bool has_positive_prefix = (view[0] == character_set<TChar>::positive_char); // const bool has_positive_prefix = (view[0] == character_set<TChar>::positive_char);
numeric_info.is_negative = (view[0] == character_set<TChar>::negative_char); // numeric_info.is_negative = (view[0] == character_set<TChar>::negative_char);
if (has_positive_prefix || numeric_info.is_negative) // if (has_positive_prefix || numeric_info.is_negative)
{ // {
view.remove_prefix(1U); // view.remove_prefix(1U);
is_valid = (view.begin() != view.end()); // is_valid = (view.begin() != view.end());
} // }
} // }
if (is_valid) // if (is_valid)
{ // {
// Look for a radix point. // // Look for a radix point.
numeric_info.radix_point_position = view.find_first_of(character_set<TChar>::radix_point); // numeric_info.radix_point_position = view.find_first_of(character_set<TChar>::radix_point);
// Look for an exponential. // // Look for an exponential.
numeric_info.exponential_position = view.find_first_of(character_set<TChar>::exponential); // numeric_info.exponential_position = view.find_first_of(character_set<TChar>::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_NODISCARD
ETL_CONSTEXPR14 ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<TValue>::value && etl::is_unsigned<TValue>::value, TValue>::type typename etl::enable_if<etl::is_integral<TValue>::value && etl::is_unsigned<TValue>::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 *= radix;
value += info.digit; value += digit;
return value; return value;
} }
@ -342,10 +345,10 @@ namespace etl
ETL_NODISCARD ETL_NODISCARD
ETL_CONSTEXPR14 ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<TValue>::value && etl::is_signed<TValue>::value, TValue>::type typename etl::enable_if<etl::is_integral<TValue>::value && etl::is_signed<TValue>::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 *= radix;
info.is_negative ? value -= info.digit : value += info.digit; is_negative ? value -= digit : value += digit;
return value; return value;
} }
@ -353,71 +356,181 @@ namespace etl
//*************************************************************************** //***************************************************************************
/// ///
//*************************************************************************** //***************************************************************************
template <typename TValue> //template <typename TValue>
ETL_NODISCARD //ETL_NODISCARD
ETL_CONSTEXPR14 //ETL_CONSTEXPR14
typename etl::enable_if<etl::is_floating_point<TValue>::value, TValue>::type //typename etl::enable_if<etl::is_floating_point<TValue>::value, TValue>::type
accumulate_integral_part(TValue value, const numeric_information& info) // accumulate_integral_part(TValue value, const numeric_information& info)
{ //{
value *= info.radix; // value *= info.radix;
info.is_negative ? value -= info.digit : value += info.digit; // info.is_negative ? value -= info.digit : value += info.digit;
return value; // return value;
} //}
//*************************************************************************** //***************************************************************************
/// ///
//*************************************************************************** //***************************************************************************
template <typename TValue> //template <typename TValue>
ETL_NODISCARD //ETL_NODISCARD
ETL_CONSTEXPR14 //ETL_CONSTEXPR14
typename etl::enable_if<etl::is_floating_point<TValue>::value, TValue>::type //typename etl::enable_if<etl::is_floating_point<TValue>::value, TValue>::type
accumulate_fractional_part(TValue value, const numeric_information& info) // accumulate_fractional_part(TValue value, const numeric_information& info)
{ //{
value /= info.radix; // value /= info.radix;
TValue d = TValue(info.digit) / info.radix; // TValue d = TValue(info.digit) / info.radix;
info.is_negative ? value -= d : value += d; // info.is_negative ? value -= d : value += d;
return value; // return value;
} //}
//***************************************************************************
///
//***************************************************************************
template <typename TValue> template <typename TValue>
struct to_integral_implementation struct to_integral_implementation
{ {
//*********************************
ETL_NODISCARD ETL_NODISCARD
ETL_CONSTEXPR14 ETL_CONSTEXPR14
to_integral_implementation(const numeric_information& info_) to_integral_implementation(etl::radix::value_type radix_)
: info(info_) : count(0)
, count(0)
, value(0) , value(0)
, is_negative(false) , is_negative(false)
, radix(radix_)
{ {
} }
//*********************************
ETL_NODISCARD ETL_NODISCARD
ETL_CONSTEXPR14 ETL_CONSTEXPR14
bool add(char c) bool add(char c)
{ {
if (valid_character_set::is_valid(c)) bool is_valid = true;
switch (count)
{ {
value = accumulate_value(value, info) case 0:
return true; {
} // Check for prefix.
else const bool has_positive_prefix = (c == valid_character_set::positive_char);
{ const bool has_negative_prefix = (c == valid_character_set::negative_char);
return false;
if (has_positive_prefix || has_negative_prefix)
{
is_negative = has_negative_prefix;
if (etl::is_unsigned<TValue>::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; int count;
TValue value; TValue value;
bool is_negative;
etl::radix::value_type radix;
}; };
} }
//*************************************************************************** //***************************************************************************
/// Text to integral from view and radix value type. /// Text to integral from view and radix value type.
//*************************************************************************** //***************************************************************************
//template <typename TValue, typename TChar>
//ETL_NODISCARD
//ETL_CONSTEXPR14
//typename etl::enable_if<etl::is_integral<TValue>::value, etl::optional<TValue> >::type
// to_arithmetic(etl::basic_string_view<TChar> view, const etl::radix::value_type radix)
//{
// using namespace etl::private_to_arithmetic;
// etl::optional<TValue> result;
// view_information<TChar> view_info;
// numeric_information numeric_info;
// to_integral_implementation<TValue> implementation(numeric_info);
// bool parsing = validate_information_from_view<TChar>(view, radix, view_info, numeric_info);
// if (parsing)
// {
// if (etl::is_unsigned<TValue>::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<TChar>::const_iterator itr = view.begin();
// while (parsing)
// {
// implementation.add(character_set<TChar>::lookup(*itr));
// ++itr;
// if (itr == view.end())
// {
// result = implementation.value;
// parsing = false;
// }
// }
// }
// }
// return result;
//}
//***************************************************************************
/// Text to integral from view and radix value type.
//***************************************************************************
template <typename TValue, typename TChar> template <typename TValue, typename TChar>
ETL_NODISCARD ETL_NODISCARD
ETL_CONSTEXPR14 ETL_CONSTEXPR14
@ -426,43 +539,42 @@ namespace etl
{ {
using namespace etl::private_to_arithmetic; using namespace etl::private_to_arithmetic;
etl::optional<TValue> result; etl::optional<TValue> result;
view_information<TChar> view_info;
numeric_information numeric_info; if (!view.empty())
to_integral_implementation<TValue> implementation(numeric_info);
bool parsing = validate_information_from_view<TChar>(view, radix, view_info, numeric_info);
if (parsing)
{ {
if (etl::is_unsigned<TValue>::value && numeric_info.is_negative) to_integral_implementation<TValue> implementation(radix);
etl::basic_string_view<TChar>::const_iterator itr = view.begin();
bool parsing = true;
while (parsing)
{ {
parsing = false; parsing = implementation.add(character_set<TChar>::lookup(*itr));
ETL_ASSERT_FAIL(ETL_ERROR(etl::to_arithmetic_signed_to_unsigned));
}
if (parsing) if (parsing)
{
// Parse the numeric part.
TValue value = 0;
etl::basic_string_view<TChar>::const_iterator itr = view.begin();
while (parsing)
{ {
implementation.add(character_set<TChar>::lookup(*itr));
++itr; ++itr;
if (itr == view.end()) 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; 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; return result;
} }

View File

@ -262,43 +262,43 @@ namespace
} }
//************************************************************************* //*************************************************************************
TEST(test_valid_float) //TEST(test_valid_float)
{ //{
const std::string text1("-123.456789"); // const std::string text1("-123.456789");
float f1 = strtof(text1.c_str(), nullptr); // float f1 = strtof(text1.c_str(), nullptr);
float f2 = etl::to_arithmetic<float>(text1.c_str(), text1.size()).value(); // float f2 = etl::to_arithmetic<float>(text1.c_str(), text1.size()).value();
CHECK_EQUAL(f1, f2); // CHECK_EQUAL(f1, f2);
const std::string text2("-1.23456789e2"); // const std::string text2("-1.23456789e2");
float f3 = etl::to_arithmetic<float>(text2.c_str(), text2.size()).value(); // float f3 = etl::to_arithmetic<float>(text2.c_str(), text2.size()).value();
CHECK_EQUAL(f1, f3); // CHECK_EQUAL(f1, f3);
} //}
//************************************************************************* //*************************************************************************
TEST(test_valid_double) //TEST(test_valid_double)
{ //{
const std::string text1("-123.45678901234567"); // const std::string text1("-123.45678901234567");
double f1 = strtod(text1.c_str(), nullptr); // double f1 = strtod(text1.c_str(), nullptr);
double f2 = etl::to_arithmetic<double>(text1.c_str(), text1.size()).value(); // double f2 = etl::to_arithmetic<double>(text1.c_str(), text1.size()).value();
CHECK_EQUAL(f1, f2); // CHECK_EQUAL(f1, f2);
} //}
//************************************************************************* //*************************************************************************
TEST(test_constexpr_integral) //TEST(test_constexpr_integral)
{ //{
constexpr const char* text{ "123" }; // constexpr const char* text{ "123" };
constexpr etl::string_view view(text, 3); // constexpr etl::string_view view(text, 3);
constexpr etl::optional<int> opt = etl::to_arithmetic<int>(view, etl::radix::decimal); // constexpr etl::optional<int> opt = etl::to_arithmetic<int>(view, etl::radix::decimal);
constexpr int i = opt.value(); // constexpr int i = opt.value();
CHECK_EQUAL(123, i); // CHECK_EQUAL(123, i);
} //}
//************************************************************************* //*************************************************************************
TEST(test_constexpr_floating_point) TEST(test_constexpr_floating_point)