Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 5 additions & 21 deletions include/iris/x4/numeric/bool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <iris/x4/core/skip_over.hpp>

#include <iris/x4/string/detail/string_parse.hpp>
#include <iris/x4/traits/numeric_traits.hpp>

#include <iris/x4/traits/char_encoding_traits.hpp>

Expand All @@ -27,23 +28,6 @@

namespace iris::x4 {

template<class CharT>
struct bool_token;

template<>
struct bool_token<char>
{
static constexpr auto true_ = "true";
static constexpr auto false_ = "false";
};

template<>
struct bool_token<char32_t>
{
static constexpr auto true_ = U"true";
static constexpr auto false_ = U"false";
};

// Default boolean policies
template<class T = bool>
struct bool_policies
Expand All @@ -53,8 +37,8 @@ struct bool_policies
parse_true(It& first, Se const& last, Attr& attr_, CaseCompare const& compare)
noexcept(noexcept(x4::move_to(T(true), attr_)))
{
using CharT = std::remove_const_t<std::iter_value_t<It>>;
if (detail::string_parse(std::basic_string_view{bool_token<CharT>::true_}, first, last, unused_container, compare)) {
using token_def = traits::numeric_token<std::iter_value_t<It>>;
if (detail::string_parse(std::basic_string_view{token_def::true_}, first, last, unused_container, compare)) {
x4::move_to(T(true), attr_);
return true;
}
Expand All @@ -66,8 +50,8 @@ struct bool_policies
parse_false(It& first, Se const& last, Attr& attr_, CaseCompare const& compare)
noexcept(noexcept(x4::move_to(T(false), attr_)))
{
using CharT = std::remove_const_t<std::iter_value_t<It>>;
if (detail::string_parse(std::basic_string_view{bool_token<CharT>::false_}, first, last, unused_container, compare)) {
using token_def = traits::numeric_token<std::iter_value_t<It>>;
if (detail::string_parse(std::basic_string_view{token_def::false_}, first, last, unused_container, compare)) {
x4::move_to(T(false), attr_);
return true;
}
Expand Down
32 changes: 18 additions & 14 deletions include/iris/x4/numeric/real.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@

#include <iris/x4/numeric/utils/extract_int.hpp>
#include <iris/x4/numeric/utils/extract_real.hpp>
#include <iris/x4/traits/numeric_traits.hpp>

#include <iris/x4/string/detail/string_parse.hpp>

#include <concepts>
#include <string_view>
#include <iterator>
#include <limits>
#include <type_traits>
Expand Down Expand Up @@ -58,7 +58,8 @@ struct ureal_policies
parse_dot(It& first, Se const& last)
noexcept(noexcept(*first) && noexcept(++first))
{
if (first == last || *first != '.') {
using CharT = std::iter_value_t<It>;
if (first == last || *first != traits::numeric_token<CharT>::dot) {
return false;
}
++first;
Expand All @@ -78,7 +79,8 @@ struct ureal_policies
parse_exp(It& first, Se const& last)
noexcept(noexcept(*first) && noexcept(++first))
{
if (first == last || (*first != 'e' && *first != 'E')) {
using token_def = traits::numeric_token<std::iter_value_t<It>>;
if (first == last || (*first != token_def::e && *first != token_def::E)) {
return false;
}
++first;
Expand Down Expand Up @@ -109,21 +111,23 @@ struct ureal_policies
[[nodiscard]] static constexpr bool
parse_nan(It& first, Se const& last, Attr& attr_)
{
using namespace std::string_view_literals;
using token_def = traits::numeric_token<std::iter_value_t<It>>;

if (first == last) return false; // end of input reached
if (*first != 'n' && *first != 'N') return false; // not "nan"
if (first == last) return false; // end of input reached
if (*first != token_def::n && *first != token_def::N) {
return false; // not "nan"
}

// nan[(...)] ?
if (detail::string_parse("nan"sv, "NAN"sv, first, last, unused_container)) {
if (first != last && *first == '(') {
if (detail::string_parse(token_def::nan, token_def::NAN_, first, last, unused_container)) {
if (first != last && *first == token_def::lparen) {
// skip trailing (...) part
It i = first;

while (++i != last && *i != ')')
while (++i != last && *i != token_def::rparen)
/* loop */;

if (i == last) return false; // no trailing ')' found, give up
if (i == last) return false; // no trailing ')' found, give up

first = ++i;
}
Expand All @@ -137,15 +141,15 @@ struct ureal_policies
[[nodiscard]] static constexpr bool
parse_inf(It& first, Se const& last, Attr& attr_)
{
using namespace std::string_view_literals;
using token_def = traits::numeric_token<std::iter_value_t<It>>;

if (first == last) return false; // end of input reached
if (*first != 'i' && *first != 'I') return false; // not "inf"
if (*first != token_def::i && *first != token_def::I) return false; // not "inf"

// inf or infinity ?
if (detail::string_parse("inf"sv, "INF"sv, first, last, unused_container)) {
if (detail::string_parse(token_def::inf, token_def::INF, first, last, unused_container)) {
// skip allowed 'inity' part of infinity
(void)detail::string_parse("inity"sv, "INITY"sv, first, last, unused_container);
(void)detail::string_parse(token_def::inity, token_def::INITY, first, last, unused_container);
attr_ = std::numeric_limits<T>::infinity();
return true;
}
Expand Down
66 changes: 37 additions & 29 deletions include/iris/x4/numeric/utils/extract_int.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,37 +98,39 @@ struct digits_traits<T, 10>
template<unsigned Radix>
struct radix_traits
{
template<class Char>
[[nodiscard]] static constexpr bool is_valid(Char ch) noexcept
template<class CharT>
[[nodiscard]] static constexpr bool is_valid(CharT ch) noexcept
{
return (ch >= '0' && ch <= (Radix > 10 ? '9' : static_cast<Char>('0' + Radix -1)))
|| (Radix > 10 && ch >= 'a' && ch <= static_cast<Char>('a' + Radix -10 -1))
|| (Radix > 10 && ch >= 'A' && ch <= static_cast<Char>('A' + Radix -10 -1));
using token_def = traits::numeric_token<CharT>;
return (ch >= token_def::_0 && ch <= (Radix > 10 ? token_def::_9 : static_cast<CharT>(token_def::_0 + Radix -1)))
|| (Radix > 10 && ch >= token_def::a && ch <= static_cast<CharT>(token_def::a + Radix -10 -1))
|| (Radix > 10 && ch >= token_def::A && ch <= static_cast<CharT>(token_def::A + Radix -10 -1));
}

template<class Char>
[[nodiscard]] static constexpr unsigned digit(Char ch)
noexcept(noexcept(traits::char_encoding_traits<Char>::encoding_type::tolower(ch)))
template<class CharT>
[[nodiscard]] static constexpr unsigned digit(CharT ch)
noexcept(noexcept(traits::char_encoding_traits<CharT>::encoding_type::tolower(ch)))
{
return (Radix <= 10 || (ch >= '0' && ch <= '9'))
? ch - '0'
: traits::char_encoding_traits<Char>::encoding_type::tolower(ch) - 'a' + 10;
using token_def = traits::numeric_token<CharT>;
return (Radix <= 10 || (ch >= token_def::_0 && ch <= token_def::_9))
? ch - token_def::_0
: traits::char_encoding_traits<CharT>::encoding_type::tolower(ch) - token_def::a + 10;
}
};

// Accumulator policies for extracting integer from a positive number.
template<unsigned Radix>
struct positive_accumulator
{
template<class T, class Char>
static constexpr void unchecked_add(T& n, Char ch)
template<class T, class CharT>
static constexpr void unchecked_add(T& n, CharT ch)
noexcept(noexcept(radix_traits<Radix>::digit(ch)))
{
n = n * T(Radix) + T(radix_traits<Radix>::digit(ch));
}

template<class T, class Char>
[[nodiscard]] static constexpr bool checked_add(T& n, Char ch)
template<class T, class CharT>
[[nodiscard]] static constexpr bool checked_add(T& n, CharT ch)
noexcept(noexcept(radix_traits<Radix>::digit(ch)))
{
// Ensure n *= Radix will not overflow
Expand All @@ -151,15 +153,15 @@ struct positive_accumulator
template<unsigned Radix>
struct negative_accumulator
{
template<class T, class Char>
static constexpr void unchecked_add(T& n, Char ch)
template<class T, class CharT>
static constexpr void unchecked_add(T& n, CharT ch)
noexcept(noexcept(radix_traits<Radix>::digit(ch)))
{
n = n * T(Radix) - T(radix_traits<Radix>::digit(ch));
}

template<class T, class Char>
[[nodiscard]] static constexpr bool checked_add(T& n, Char ch)
template<class T, class CharT>
[[nodiscard]] static constexpr bool checked_add(T& n, CharT ch)
noexcept(noexcept(radix_traits<Radix>::digit(ch)))
{
// Ensure n *= Radix will not underflow
Expand Down Expand Up @@ -190,10 +192,10 @@ struct int_extractor
) &&
traits::check_overflow<T>::value;

template<class Char, class T>
template<class CharT, class T>
requires need_check_overflow<T>
[[nodiscard]] static constexpr bool
call(Char ch, std::size_t count, T& n)
call(CharT ch, std::size_t count, T& n)
noexcept(
noexcept(Accumulator::unchecked_add(n, ch)) &&
noexcept(Accumulator::checked_add(n, ch))
Expand All @@ -211,19 +213,19 @@ struct int_extractor
return true;
}

template<class Char, class T>
template<class CharT, class T>
requires (!need_check_overflow<T>)
[[nodiscard]] static constexpr bool
call(Char ch, std::size_t /*count*/, T& n)
call(CharT ch, std::size_t /*count*/, T& n)
noexcept(noexcept(Accumulator::unchecked_add(n, ch)))
{
Accumulator::unchecked_add(n, ch);
return true;
}

template<class Char>
template<class CharT>
[[nodiscard]] static constexpr bool
call(Char /*ch*/, std::size_t /*count*/, unused_type const&) noexcept
call(CharT /*ch*/, std::size_t /*count*/, unused_type const&) noexcept
{
return true;
}
Expand Down Expand Up @@ -274,11 +276,13 @@ struct extract_int
using extractor = int_extractor<Radix, Accumulator, MaxDigits>;
using char_type = std::iter_value_t<It>;

using token_def = traits::numeric_token<std::iter_value_t<It>>;

It it = first;
std::size_t leading_zeros = 0;
if constexpr (!Accumulate) {
// skip leading zeros
while (it != last && *it == '0' && leading_zeros < static_cast<std::size_t>(MaxDigits)) {
while (it != last && *it == token_def::_0 && leading_zeros < static_cast<std::size_t>(MaxDigits)) {
++it;
++leading_zeros;
}
Expand Down Expand Up @@ -359,11 +363,13 @@ struct extract_int<T, Radix, 1, -1, Accumulator, Accumulate>
using extractor = int_extractor<Radix, Accumulator, -1>;
using char_type = std::iter_value_t<It>;

using token_def = traits::numeric_token<std::iter_value_t<It>>;

It it = first;
std::size_t count = 0;
if constexpr (!Accumulate) {
// skip leading zeros
while (it != last && *it == '0') {
while (it != last && *it == token_def::_0) {
++it;
++count;
}
Expand Down Expand Up @@ -443,12 +449,14 @@ extract_sign(It& first, Se const& last)
noexcept(++first)
)
{
using token_def = traits::numeric_token<std::iter_value_t<It>>;

(void)last;
assert(first != last); // precondition

// Extract the sign
bool const neg = *first == '-';
if (neg || *first == '+') {
bool const neg = *first == token_def::minus;
if (neg || *first == token_def::plus) {
++first;
return neg;
}
Expand Down
2 changes: 1 addition & 1 deletion include/iris/x4/numeric/utils/extract_real.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ struct extract_real

// Start by parsing the sign. neg will be true if
// we got a "-" sign, false otherwise.
bool neg = Policy::parse_sign(first, last);
bool const neg = Policy::parse_sign(first, last);

// Now attempt to parse an integer
T n = 0;
Expand Down
2 changes: 2 additions & 0 deletions include/iris/x4/string/detail/string_parse.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ string_parse(
static_assert(std::same_as<traits::attribute_category_t<synthesized_value_type>, traits::container_attr>);
using value_type = traits::container_value<synthesized_value_type>::type;
static_assert(!CharLike<value_type> || !CharIncompatibleWith<value_type, CharT>, "Mixing incompatible char types is not allowed");
static_assert(!CharIncompatibleWith<std::iter_value_t<It>, CharT>, "Mixing incompatible char types is not allowed");

It it = first;
auto stri = str.begin();
Expand Down Expand Up @@ -81,6 +82,7 @@ string_parse(
static_assert(std::same_as<traits::attribute_category_t<synthesized_value_type>, traits::container_attr>);
using value_type = traits::container_value<synthesized_value_type>::type;
static_assert(!CharLike<value_type> || !CharIncompatibleWith<value_type, CharT>, "Mixing incompatible char types is not allowed");
static_assert(!CharIncompatibleWith<std::iter_value_t<It>, CharT>, "Mixing incompatible char types is not allowed");

auto uc_it = ucstr.begin();
auto uc_last = ucstr.end();
Expand Down
50 changes: 50 additions & 0 deletions include/iris/x4/traits/numeric_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,63 @@
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
==============================================================================*/

#include <string_view>
#include <limits>
#include <type_traits>

namespace iris::x4::traits {

// Customization points for numeric operations

template<class CharT>
struct numeric_token;

#define IRIS_X4_DEF(CharT, XSTR) \
template<> \
struct numeric_token<CharT> \
{ \
inline static constexpr CharT a = XSTR('a'); \
inline static constexpr CharT A = XSTR('A'); \
inline static constexpr CharT e = XSTR('e'); \
inline static constexpr CharT E = XSTR('E'); \
inline static constexpr CharT n = XSTR('n'); \
inline static constexpr CharT N = XSTR('N'); \
inline static constexpr CharT i = XSTR('i'); \
inline static constexpr CharT I = XSTR('I'); \
\
inline static constexpr CharT _0 = XSTR('0'); \
inline static constexpr CharT _9 = XSTR('9'); \
\
inline static constexpr CharT minus = XSTR('-'); \
inline static constexpr CharT plus = XSTR('+'); \
inline static constexpr CharT dot = XSTR('.'); \
inline static constexpr CharT lparen = XSTR('('); \
inline static constexpr CharT rparen = XSTR(')'); \
\
inline static constexpr std::basic_string_view<CharT> nan = XSTR("nan"); \
inline static constexpr std::basic_string_view<CharT> NAN_ = XSTR("NAN"); \
inline static constexpr std::basic_string_view<CharT> inf = XSTR("inf"); \
inline static constexpr std::basic_string_view<CharT> inity = XSTR("inity"); \
inline static constexpr std::basic_string_view<CharT> INF = XSTR("INF"); \
inline static constexpr std::basic_string_view<CharT> INITY = XSTR("INITY"); \
\
inline static constexpr std::basic_string_view<CharT> true_ = XSTR("true"); \
inline static constexpr std::basic_string_view<CharT> false_ = XSTR("false"); \
};

#define IRIS_X4_XSTR_char(str) str
IRIS_X4_DEF(char, IRIS_X4_XSTR_char)
#undef IRIS_X4_XSTR_char

#ifdef IRIS_X4_UNICODE
# define IRIS_X4_XSTR_u32(str) U##str
IRIS_X4_DEF(char32_t, IRIS_X4_XSTR_u32)
# undef IRIS_X4_XSTR_u32
#endif

#undef IRIS_X4_DEF


template<class T>
struct pow10_helper;

Expand Down
Loading