First implementation ideas

This commit is contained in:
John Wellbelove 2022-09-18 09:54:17 +01:00
parent ce2a8ba0fc
commit 3d412e6e7d
6 changed files with 426 additions and 4 deletions

View File

@ -99,5 +99,6 @@ SOFTWARE.
#define ETL_BYTE_STREAM_FILE_ID "66"
#define ETL_BIP_BUFFER_SPSC_ATOMIC_FILE_ID "67"
#define ETL_REFERENCE_COUNTED_OBJECT_FILE_ID "68"
#define ETL_TO_ARITHMETIC_FILE_ID "69"
#endif

View File

@ -435,7 +435,7 @@ namespace etl
ETL_CONSTEXPR14 bool starts_with(etl::basic_string_view<T, TTraits> 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<T, TTraits> 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);
}
//*************************************************************************

345
include/etl/to_arithmetic.h Normal file
View File

@ -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 <typename TChar>
struct character_set;
template <>
struct character_set<char>
{
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<wchar_t>
{
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<char16_t>
{
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<char32_t>
{
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 <typename TChar>
bool has_valid_characters(etl::basic_string_view<TChar> view, etl::basic_string_view<TChar> valid_characters)
{
if (valid_characters.empty())
{
return false;
}
size_t position = view.find_first_not_of(valid_characters);
return position == etl::basic_string_view<TChar>::npos;
}
//*******************************
template <typename TChar>
char get_digit_value(TChar c)
{
size_t length = etl::strlen(character_set<TChar>::numeric_chars);
for (int i = 0; i < length; ++i)
{
if (c == character_set<TChar>::numeric_chars[i])
{
return (i < 16) ? i : i - 6;
}
}
return 0;
}
//*******************************
template <typename TChar>
struct processed_string
{
etl::basic_string_view<TChar> view;
bool is_negative;
bool is_valid;
};
//***************************************************************************
///
//***************************************************************************
template <typename TChar>
processed_string<TChar> preprocess_string(etl::basic_string_view<TChar> 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<TChar>::positive_char);
const bool has_negative_prefix = (view[0] == character_set<TChar>::negative_char);
// Remove positive or negative prefixes.
if (has_positive_prefix || has_negative_prefix)
{
view.remove_prefix(1);
}
etl::basic_string_view<TChar> valid_characters;
switch (radix)
{
case etl::radix::binary: { valid_characters = etl::basic_string_view<TChar>(character_set<TChar>::numeric_chars, binary_length); break; }
case etl::radix::octal: { valid_characters = etl::basic_string_view<TChar>(character_set<TChar>::numeric_chars, octal_length); break; }
case etl::radix::decimal: { valid_characters = etl::basic_string_view<TChar>(character_set<TChar>::numeric_chars, decimal_length); break; }
case etl::radix::hex: { valid_characters = etl::basic_string_view<TChar>(character_set<TChar>::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<TChar>{ view, has_negative_prefix, is_valid };
}
}
//***************************************************************************
///
//***************************************************************************
template <typename T, typename TChar>
ETL_CONSTEXPR14 typename etl::enable_if<etl::is_integral<T>::value, etl::optional<T> >::type
to_integer(etl::basic_string_view<TChar> view, const etl::radix::value_type radix)
{
using namespace etl::private_to_arithmetic;
processed_string<TChar> data = preprocess_string(view, radix);
etl::optional<T> 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<T>::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<TChar>::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<TChar>::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 <typename T, typename TChar>
ETL_CONSTEXPR14 typename etl::enable_if<etl::is_integral<T>::value, etl::optional<T> >::type
to_integer(const etl::basic_string_view<TChar>& view)
{
return etl::to_integer<T, TChar>(view, etl::radix::decimal);
}
//***************************************************************************
///
//***************************************************************************
template <typename T, typename TChar>
ETL_CONSTEXPR14 typename etl::enable_if<etl::is_integral<T>::value, etl::optional<T> >::type
to_integer(const etl::basic_string_view<TChar>& view, const etl::basic_format_spec<etl::ibasic_string<TChar> >& spec)
{
return etl::to_integer<T, TChar>(view, spec.get_base());
}
//***************************************************************************
///
//***************************************************************************
template <typename T, typename TChar>
ETL_CONSTEXPR14 typename etl::enable_if<etl::is_integral<T>::value, etl::optional<T> >::type
to_integer(const TChar* cp, size_t length, const etl::radix::value_type radix)
{
return etl::to_integer<T, TChar>(etl::basic_string_view<TChar>(cp, length), radix);
}
//***************************************************************************
///
//***************************************************************************
template <typename T, typename TChar>
ETL_CONSTEXPR14 typename etl::enable_if<etl::is_integral<T>::value, etl::optional<T> >::type
to_integer(const TChar* cp, size_t length)
{
return etl::to_integer<T, TChar>(etl::basic_string_view<TChar>(cp, length), etl::radix::decimal);;
}
//***************************************************************************
///
//***************************************************************************
template <typename T, typename TChar>
ETL_CONSTEXPR14 typename etl::enable_if<etl::is_integral<T>::value, etl::optional<T> >::type
to_integer(const TChar* cp, size_t length, const typename etl::private_basic_format_spec::base_spec& spec)
{
return etl::to_integer<T, TChar>(etl::basic_string_view<TChar>(cp, length), spec.base);;
}
//***************************************************************************
///
//***************************************************************************
template <typename T, typename TChar>
ETL_CONSTEXPR14 typename etl::enable_if<etl::is_integral<T>::value, etl::optional<T> >::type
to_integer(const etl::ibasic_string<TChar>& str, const etl::radix::value_type radix)
{
return etl::to_integer<T, TChar>(etl::basic_string_view<TChar>(str), radix);;
}
//***************************************************************************
///
//***************************************************************************
template <typename T, typename TChar>
ETL_CONSTEXPR14 typename etl::enable_if<etl::is_integral<T>::value, etl::optional<T> >::type
to_integer(const etl::ibasic_string<TChar>& str)
{
return etl::to_integer<T, TChar>(etl::basic_string_view<TChar>(str), radix);;
}
//***************************************************************************
///
//***************************************************************************
template <typename T, typename TChar>
ETL_CONSTEXPR14 typename etl::enable_if<etl::is_integral<T>::value, etl::optional<T> >::type
to_integer(const etl::ibasic_string<TChar>& str, const etl::basic_format_spec<etl::ibasic_string<TChar> >& spec)
{
return etl::to_integer<T, TChar>(etl::basic_string_view<TChar>(str), spec);;
}
template <typename T, typename TChar>
ETL_CONSTEXPR14 typename etl::enable_if<etl::is_integral<T>::value, etl::optional<T> >::type
to_arithmetic(etl::basic_string_view<TChar> view, const etl::radix::value_type radix)
{
return to_integer<T>(view, radix);
}
template <typename T, typename TChar>
ETL_CONSTEXPR14 typename etl::enable_if<etl::is_floating_point<T>::value, etl::optional<T> >::type
to_arithmetic(etl::basic_string_view<TChar> view, const etl::radix::value_type radix)
{
return to_floating_point<T>(view, radix);
}
}

View File

@ -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 <ostream>
#include <sstream>
#include <iomanip>
#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<int8_t>(pp, strlen(pp), etl::dec).value());
CHECK_EQUAL(std::numeric_limits<int64_t>::min(), etl::to_integer<int64_t>(huge_n.c_str(), huge_n.size(), etl::hex).value());
CHECK_EQUAL(std::numeric_limits<int64_t>::max(), etl::to_integer<int64_t>(huge_p.c_str(), huge_p.size(), etl::hex).value());
//CHECK_EQUAL(123, etl::to_integer<char>(pp, 3, etl::dec));
//CHECK_EQUAL(123, etl::to_integer<char>(pp, 3, etl::radix::decimal));
//CHECK_EQUAL(123, etl::to_integer<char>(pp, 3, etl::radix(etl::radix::decimal)));
//CHECK_EQUAL(123, etl::to_integer<char>(pp, 3, 10));
}
}
}

View File

@ -2588,6 +2588,7 @@
<ClInclude Include="..\..\include\etl\task.h" />
<ClInclude Include="..\..\include\etl\threshold.h" />
<ClInclude Include="..\..\include\etl\timer.h" />
<ClInclude Include="..\..\include\etl\to_arithmetic.h" />
<ClInclude Include="..\..\include\etl\to_string.h" />
<ClInclude Include="..\..\include\etl\to_u16string.h" />
<ClInclude Include="..\..\include\etl\to_u32string.h" />
@ -12107,6 +12108,7 @@
<ClCompile Include="..\test_state_chart_compile_time_with_data_parameter.cpp" />
<ClCompile Include="..\test_state_chart_with_data_parameter.cpp" />
<ClCompile Include="..\test_state_chart_with_rvalue_data_parameter.cpp" />
<ClCompile Include="..\test_string_to_arithmetic.cpp" />
<ClCompile Include="..\test_string_utilities_std.cpp" />
<ClCompile Include="..\test_string_char.cpp" />
<ClCompile Include="..\test_string_char_external_buffer.cpp" />

View File

@ -1338,6 +1338,9 @@
<ClInclude Include="..\..\include\etl\private\diagnostic_uninitialized_push.h">
<Filter>ETL\Private</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\to_arithmetic.h">
<Filter>ETL\Strings</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\test_string_char.cpp">
@ -3371,6 +3374,9 @@
<ClCompile Include="..\test_bitset_new_ext_explicit_single_element_type.cpp">
<Filter>Tests\Binary</Filter>
</ClCompile>
<ClCompile Include="..\test_string_to_arithmetic.cpp">
<Filter>Tests\Strings</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\library.properties">