Skip to content

Commit

Permalink
Integer reader refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
eliaskosunen committed Jan 7, 2024
1 parent 85ec3eb commit c83764c
Show file tree
Hide file tree
Showing 6 changed files with 479 additions and 679 deletions.
50 changes: 23 additions & 27 deletions src/scn/impl/reader/float_reader.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ namespace scn {
SCN_EXPECT(m_kind != float_kind::tbd);

const std::ptrdiff_t sign_len =
m_sign != numeric_reader_base::sign::default_sign ? 1 : 0;
m_sign != sign_type::default_sign ? 1 : 0;

SCN_TRY(n, parse_value_impl(value));
return n + sign_len + ranges::ssize(m_thsep_indices);
Expand All @@ -118,8 +118,10 @@ namespace scn {
scan_expected<simple_borrowed_iterator_t<Range>> read_source_impl(
Range&& range)
{
SCN_TRY(it, numeric_reader_base::read_sign(range, m_sign)
.transform_error(make_eof_scan_error));
SCN_TRY(sign_result, parse_numeric_sign(range).transform_error(
make_eof_scan_error));
auto it = sign_result.first;
m_sign = sign_result.second;

auto digits_begin = it;
auto r = ranges::subrange{it, ranges::end(range)};
Expand Down Expand Up @@ -178,7 +180,7 @@ namespace scn {

if (!m_thsep_indices.empty()) {
SCN_EXPECT(m_integral_part_length >= 0);
if (auto e = this->check_thsep_grouping(
if (auto e = check_thsep_grouping(
ranges::subrange{
digits_begin,
ranges::next(digits_begin,
Expand All @@ -201,15 +203,15 @@ namespace scn {
thsep_allowed)) {
return read_while1_code_unit(
SCN_FWD(range), [&](char_type ch) SCN_NOEXCEPT {
return numeric_reader_base::char_to_int(ch) < 10 ||
return char_to_int(ch) < 10 ||
ch == m_locale_options.thousands_sep;
});
}

return read_while1_code_unit(
SCN_FWD(range), [](char_type ch) SCN_NOEXCEPT {
return numeric_reader_base::char_to_int(ch) < 10;
});
return read_while1_code_unit(SCN_FWD(range),
[](char_type ch) SCN_NOEXCEPT {
return char_to_int(ch) < 10;
});
}
template <typename Range>
parse_expected<simple_borrowed_iterator_t<Range>> read_hex_digits(
Expand All @@ -220,15 +222,15 @@ namespace scn {
thsep_allowed)) {
return read_while1_code_unit(
SCN_FWD(range), [&](char_type ch) SCN_NOEXCEPT {
return numeric_reader_base::char_to_int(ch) < 16 ||
return char_to_int(ch) < 16 ||
ch == m_locale_options.thousands_sep;
});
}

return read_while1_code_unit(
SCN_FWD(range), [](char_type ch) SCN_NOEXCEPT {
return numeric_reader_base::char_to_int(ch) < 16;
});
return read_while1_code_unit(SCN_FWD(range),
[](char_type ch) SCN_NOEXCEPT {
return char_to_int(ch) < 16;
});
}
template <typename Range>
parse_expected<simple_borrowed_iterator_t<Range>> read_hex_prefix(
Expand Down Expand Up @@ -318,21 +320,16 @@ namespace scn {
if (auto r = read_one_of_code_unit(range, exp)) {
auto beg_exp_it = ranges::begin(range);
auto it = *r;
numeric_reader_base::sign exp_sign{
numeric_reader_base::sign::default_sign};

if (auto r_sign = numeric_reader_base::read_sign(
ranges::subrange{it, ranges::end(range)},
exp_sign)) {
it = *r_sign;
if (auto r_sign = parse_numeric_sign(
ranges::subrange{it, ranges::end(range)})) {
it = r_sign->first;
}

if (auto r_exp = read_while1_code_unit(
ranges::subrange{it, ranges::end(range)},
[](char_type ch) SCN_NOEXCEPT {
return numeric_reader_base::char_to_int(ch) <
10;
});
[](char_type ch)
SCN_NOEXCEPT { return char_to_int(ch) < 10; });
SCN_UNLIKELY(!r_exp)) {
it = beg_exp_it;
}
Expand Down Expand Up @@ -559,7 +556,7 @@ namespace scn {
T setsign(T value) const
{
SCN_EXPECT(std::isnan(value) || value >= static_cast<T>(0.0));
if (m_sign == numeric_reader_base::sign::minus_sign) {
if (m_sign == sign_type::minus_sign) {
return -value;
}
return value;
Expand All @@ -572,8 +569,7 @@ namespace scn {
std::string m_thsep_indices{};
contiguous_range_factory<CharT> m_nan_payload_buffer{};
std::ptrdiff_t m_integral_part_length{-1};
numeric_reader_base::sign m_sign{
numeric_reader_base::sign::default_sign};
sign_type m_sign{sign_type::default_sign};
float_kind m_kind{float_kind::tbd};
};

Expand Down
103 changes: 52 additions & 51 deletions src/scn/impl/reader/integer_reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,12 @@ namespace scn {
static constexpr auto abs_int_min =
static_cast<utype>(int_max + 1);

int_reader_state(int base, numeric_reader_base::sign s)
int_reader_state(int base, sign_type s)
: ubase(static_cast<utype>(base)),
sign(s),
limit([&]() -> utype {
if constexpr (std::is_signed_v<T>) {
if (sign ==
numeric_reader_base::sign::minus_sign) {
if (sign == sign_type::minus_sign) {
return abs_int_min;
}
return int_max;
Expand All @@ -169,7 +168,7 @@ namespace scn {

utype accumulator{};
const utype ubase;
const numeric_reader_base::sign sign;
const sign_type sign;
const utype limit;
const std::pair<utype, utype> cutlimits;
};
Expand All @@ -179,7 +178,7 @@ namespace scn {
int_reader_state<T>& state)
{
auto overflow_error_msg = [sign = state.sign]() {
if (sign == numeric_reader_base::sign::minus_sign) {
if (sign == sign_type::minus_sign) {
return "Out of range: integer overflow";
}
return "Out of range: integer underflow";
Expand Down Expand Up @@ -209,8 +208,7 @@ namespace scn {
{
using utype = typename int_reader_state<T>::utype;

const auto digit =
static_cast<utype>(numeric_reader_base::char_to_int(ch));
const auto digit = static_cast<utype>(char_to_int(ch));
if (digit >= state.ubase) {
return {false, {}};
}
Expand Down Expand Up @@ -389,9 +387,9 @@ namespace scn {
template <typename T>
void store_value(const int_reader_state<T>& state,
T& value,
numeric_reader_base::sign sign)
sign_type sign)
{
if (sign == numeric_reader_base::sign::minus_sign) {
if (sign == sign_type::minus_sign) {
if (SCN_UNLIKELY(state.accumulator == state.abs_int_min)) {
value = std::numeric_limits<T>::min();
}
Expand All @@ -411,13 +409,13 @@ namespace scn {
template <typename T>
void store_value_if_out_of_range(const scan_error& err,
T& value,
numeric_reader_base::sign sign)
sign_type sign)
{
if (err.code() != scan_error::value_out_of_range) {
return;
}

if (sign == numeric_reader_base::sign::minus_sign) {
if (sign == sign_type::minus_sign) {
value = std::numeric_limits<T>::min();
}
else {
Expand All @@ -427,23 +425,22 @@ namespace scn {

} // namespace

template <typename CharT>
template <typename T>
scan_expected<ranges::iterator_t<std::basic_string_view<CharT>>>
integer_reader<CharT>::parse_value_impl(T& value)
template <typename CharT, typename T>
auto parse_integer_value(std::basic_string_view<CharT> source,
T& value,
sign_type sign,
int base)
-> scan_expected<typename std::basic_string_view<CharT>::iterator>
{
auto source = this->m_buffer.view();

SCN_EXPECT(!source.empty());
SCN_EXPECT(std::is_signed_v<T> ||
m_sign == numeric_reader_base::sign::plus_sign);
SCN_EXPECT(m_sign != numeric_reader_base::sign::default_sign);
SCN_EXPECT(m_base > 0);
SCN_EXPECT(std::is_signed_v<T> || sign == sign_type::plus_sign);
SCN_EXPECT(sign != sign_type::default_sign);
SCN_EXPECT(base > 0);

int_reader_state<T> state{m_base, m_sign};
int_reader_state<T> state{base, sign};
auto it = source.begin();

if (this->char_to_int(*it) >= m_base) {
if (char_to_int(*it) >= base) {
SCN_UNLIKELY_ATTR
return unexpected_scan_error(scan_error::invalid_scanned_value,
"Invalid integer value");
Expand All @@ -458,7 +455,7 @@ namespace scn {
if (auto err = do_read_decimal_fast64<T>(
state, it, source.end(), stop_reading);
SCN_UNLIKELY(!err)) {
store_value_if_out_of_range(err, value, m_sign);
store_value_if_out_of_range(err, value, sign);
return unexpected(err);
}
if constexpr (!can_do_fast64_multiple_times<T>()) {
Expand All @@ -471,20 +468,21 @@ namespace scn {
for (; /*!stop_reading &&*/ it != source.end(); ++it) {
if (const auto [keep_going, err] = do_single_char(*it, state);
SCN_UNLIKELY(!err)) {
store_value_if_out_of_range(err, value, m_sign);
store_value_if_out_of_range(err, value, sign);
return unexpected(err);
}
else if (!keep_going) {
break;
}
}

store_value(state, value, m_sign);
store_value(state, value, sign);
return it;
}

template <typename T>
void parse_int_value_exhaustive_valid(std::string_view source, T& value)
void parse_integer_value_exhaustive_valid(std::string_view source,
T& value)
{
SCN_EXPECT(!source.empty());

Expand All @@ -496,7 +494,7 @@ namespace scn {
}
}
SCN_EXPECT(!source.empty());
SCN_EXPECT(numeric_reader_base::char_to_int(source.front()) < 10);
SCN_EXPECT(char_to_int(source.front()) < 10);

while (source.size() >= 4) {
const auto n = std::min(source.size(), size_t{8});
Expand All @@ -505,7 +503,7 @@ namespace scn {

#ifndef NDEBUG
for (char ch : source.substr(0, n)) {
SCN_EXPECT(numeric_reader_base::char_to_int(ch) < 10);
SCN_EXPECT(char_to_int(ch) < 10);
}
#endif

Expand Down Expand Up @@ -534,7 +532,7 @@ namespace scn {
}

for (auto ch : source) {
auto digit = numeric_reader_base::char_to_int(ch);
auto digit = char_to_int(ch);
SCN_EXPECT(digit < 10);
value *= 10;
value += digit;
Expand All @@ -547,67 +545,70 @@ namespace scn {
}
}

#define SCN_DEFINE_INTEGER_READER_TEMPLATE(CharT, IntT) \
template auto integer_reader<CharT>::parse_value_impl(IntT&) \
-> scan_expected<ranges::iterator_t<std::basic_string_view<CharT>>>;
#define SCN_DEFINE_INTEGER_READER_TEMPLATE(CharT, IntT) \
template auto parse_integer_value(std::basic_string_view<CharT> source, \
IntT& value, sign_type sign, int base) \
-> scan_expected<typename std::basic_string_view<CharT>::iterator>;

#if !SCN_DISABLE_TYPE_SCHAR
SCN_DEFINE_INTEGER_READER_TEMPLATE(char, signed char)
SCN_DEFINE_INTEGER_READER_TEMPLATE(wchar_t, signed char)
template void parse_int_value_exhaustive_valid(std::string_view,
signed char&);
template void parse_integer_value_exhaustive_valid(std::string_view,
signed char&);
#endif
#if !SCN_DISABLE_TYPE_SHORT
SCN_DEFINE_INTEGER_READER_TEMPLATE(char, short)
SCN_DEFINE_INTEGER_READER_TEMPLATE(wchar_t, short)
template void parse_int_value_exhaustive_valid(std::string_view,
short&);
template void parse_integer_value_exhaustive_valid(std::string_view,
short&);
#endif
#if !SCN_DISABLE_TYPE_INT
SCN_DEFINE_INTEGER_READER_TEMPLATE(char, int)
SCN_DEFINE_INTEGER_READER_TEMPLATE(wchar_t, int)
template void parse_int_value_exhaustive_valid(std::string_view, int&);
template void parse_integer_value_exhaustive_valid(std::string_view,
int&);
#endif
#if !SCN_DISABLE_TYPE_LONG
SCN_DEFINE_INTEGER_READER_TEMPLATE(char, long)
SCN_DEFINE_INTEGER_READER_TEMPLATE(wchar_t, long)
template void parse_int_value_exhaustive_valid(std::string_view, long&);
template void parse_integer_value_exhaustive_valid(std::string_view,
long&);
#endif
#if !SCN_DISABLE_TYPE_LONG_LONG
SCN_DEFINE_INTEGER_READER_TEMPLATE(char, long long)
SCN_DEFINE_INTEGER_READER_TEMPLATE(wchar_t, long long)
template void parse_int_value_exhaustive_valid(std::string_view,
long long&);
template void parse_integer_value_exhaustive_valid(std::string_view,
long long&);
#endif
#if !SCN_DISABLE_TYPE_UCHAR
SCN_DEFINE_INTEGER_READER_TEMPLATE(char, unsigned char)
SCN_DEFINE_INTEGER_READER_TEMPLATE(wchar_t, unsigned char)
template void parse_int_value_exhaustive_valid(std::string_view,
unsigned char&);
template void parse_integer_value_exhaustive_valid(std::string_view,
unsigned char&);
#endif
#if !SCN_DISABLE_TYPE_USHORT
SCN_DEFINE_INTEGER_READER_TEMPLATE(char, unsigned short)
SCN_DEFINE_INTEGER_READER_TEMPLATE(wchar_t, unsigned short)
template void parse_int_value_exhaustive_valid(std::string_view,
unsigned short&);
template void parse_integer_value_exhaustive_valid(std::string_view,
unsigned short&);
#endif
#if !SCN_DISABLE_TYPE_UINT
SCN_DEFINE_INTEGER_READER_TEMPLATE(char, unsigned int)
SCN_DEFINE_INTEGER_READER_TEMPLATE(wchar_t, unsigned int)
template void parse_int_value_exhaustive_valid(std::string_view,
unsigned int&);
template void parse_integer_value_exhaustive_valid(std::string_view,
unsigned int&);
#endif
#if !SCN_DISABLE_TYPE_ULONG
SCN_DEFINE_INTEGER_READER_TEMPLATE(char, unsigned long)
SCN_DEFINE_INTEGER_READER_TEMPLATE(wchar_t, unsigned long)
template void parse_int_value_exhaustive_valid(std::string_view,
unsigned long&);
template void parse_integer_value_exhaustive_valid(std::string_view,
unsigned long&);
#endif
#if !SCN_DISABLE_TYPE_ULONG_LONG
SCN_DEFINE_INTEGER_READER_TEMPLATE(char, unsigned long long)
SCN_DEFINE_INTEGER_READER_TEMPLATE(wchar_t, unsigned long long)
template void parse_int_value_exhaustive_valid(std::string_view,
unsigned long long&);
template void parse_integer_value_exhaustive_valid(std::string_view,
unsigned long long&);
#endif

#undef SCN_DEFINE_INTEGER_READER_TEMPLATE
Expand Down
Loading

0 comments on commit c83764c

Please sign in to comment.