mirror of
https://github.com/ETLCPP/etl.git
synced 2026-04-30 19:09:10 +08:00
First implementation ideas
This commit is contained in:
parent
ce2a8ba0fc
commit
3d412e6e7d
@ -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
|
||||
|
||||
@ -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
345
include/etl/to_arithmetic.h
Normal 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);
|
||||
}
|
||||
}
|
||||
68
test/test_string_to_arithmetic.cpp
Normal file
68
test/test_string_to_arithmetic.cpp
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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" />
|
||||
|
||||
@ -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">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user