Commit c86a6cf6 authored by Dominik Charousset's avatar Dominik Charousset

Add parser for signed and unsigned integer types

parent b266f584
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <cstdint>
#include <type_traits>
#include "caf/config.hpp"
#include "caf/detail/parser/add_ascii.hpp"
#include "caf/detail/parser/chars.hpp"
#include "caf/detail/parser/is_char.hpp"
#include "caf/detail/parser/is_digit.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/parser/sub_ascii.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/pec.hpp"
CAF_PUSH_UNUSED_LABEL_WARNING
#include "caf/detail/parser/fsm.hpp"
namespace caf {
namespace detail {
namespace parser {
/// Reads a number, i.e., on success produces either an `int64_t` or a
/// `double`.
template <class Iterator, class Sentinel, class Consumer>
void read_signed_integer(state<Iterator, Sentinel>& ps, Consumer& consumer) {
using value_type = typename Consumer::value_type;
static_assert(std::is_integral<value_type>::value
&& std::is_signed<value_type>::value,
"expected a signed integer type");
value_type result = 0;
// Computes the result on success.
auto g = caf::detail::make_scope_guard([&] {
if (ps.code <= pec::trailing_character) {
consumer.value(std::move(result));
}
});
// clang-format off
// Definition of our parser FSM.
start();
state(init) {
transition(init, " \t")
transition(has_plus, '+')
transition(has_minus, '-')
transition(pos_zero, '0')
epsilon(has_plus)
}
// "+" or "-" alone aren't numbers.
state(has_plus) {
transition(pos_zero, '0')
epsilon(pos_dec)
}
state(has_minus) {
transition(neg_zero, '0')
epsilon(neg_dec)
}
// Disambiguate base.
term_state(pos_zero) {
transition(start_pos_bin, "bB")
transition(start_pos_hex, "xX")
epsilon(pos_oct)
}
term_state(neg_zero) {
transition(start_neg_bin, "bB")
transition(start_neg_hex, "xX")
epsilon(neg_oct)
}
// Binary integers.
state(start_pos_bin) {
epsilon(pos_bin)
}
term_state(pos_bin) {
transition(pos_bin, "01", add_ascii<2>(result, ch), pec::integer_overflow)
}
state(start_neg_bin) {
epsilon(neg_bin)
}
term_state(neg_bin) {
transition(neg_bin, "01", sub_ascii<2>(result, ch), pec::integer_underflow)
}
// Octal integers.
state(start_pos_oct) {
epsilon(pos_oct)
}
term_state(pos_oct) {
transition(pos_oct, octal_chars, add_ascii<8>(result, ch),
pec::integer_overflow)
}
state(start_neg_oct) {
epsilon(neg_oct)
}
term_state(neg_oct) {
transition(neg_oct, octal_chars, sub_ascii<8>(result, ch),
pec::integer_underflow)
}
// Hexal integers.
state(start_pos_hex) {
epsilon(pos_hex)
}
term_state(pos_hex) {
transition(pos_hex, hexadecimal_chars, add_ascii<16>(result, ch),
pec::integer_overflow)
}
state(start_neg_hex) {
epsilon(neg_hex)
}
term_state(neg_hex) {
transition(neg_hex, hexadecimal_chars, sub_ascii<16>(result, ch),
pec::integer_underflow)
}
// Reads the integer part of the mantissa or a positive decimal integer.
term_state(pos_dec) {
transition(pos_dec, decimal_chars, add_ascii<10>(result, ch),
pec::integer_overflow)
}
// Reads the integer part of the mantissa or a negative decimal integer.
term_state(neg_dec) {
transition(neg_dec, decimal_chars, sub_ascii<10>(result, ch),
pec::integer_underflow)
}
fin();
// clang-format on
}
} // namespace parser
} // namespace detail
} // namespace caf
#include "caf/detail/parser/fsm_undef.hpp"
CAF_POP_WARNINGS
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <cstdint>
#include <type_traits>
#include "caf/config.hpp"
#include "caf/detail/parser/add_ascii.hpp"
#include "caf/detail/parser/chars.hpp"
#include "caf/detail/parser/is_char.hpp"
#include "caf/detail/parser/is_digit.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/parser/sub_ascii.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/pec.hpp"
CAF_PUSH_UNUSED_LABEL_WARNING
#include "caf/detail/parser/fsm.hpp"
namespace caf {
namespace detail {
namespace parser {
/// Reads a number, i.e., on success produces either an `int64_t` or a
/// `double`.
template <class Iterator, class Sentinel, class Consumer>
void read_unsigned_integer(state<Iterator, Sentinel>& ps, Consumer& consumer) {
using value_type = typename Consumer::value_type;
static_assert(std::is_integral<value_type>::value
&& std::is_unsigned<value_type>::value,
"expected an unsigned integer type");
value_type result = 0;
// Computes the result on success.
auto g = caf::detail::make_scope_guard([&] {
if (ps.code <= pec::trailing_character) {
consumer.value(std::move(result));
}
});
// clang-format off
// Definition of our parser FSM.
start();
state(init) {
transition(init, " \t")
transition(has_plus, '+')
transition(pos_zero, '0')
epsilon(has_plus)
}
// "+" or "-" alone aren't numbers.
state(has_plus) {
transition(pos_zero, '0')
epsilon(pos_dec)
}
// Disambiguate base.
term_state(pos_zero) {
transition(start_pos_bin, "bB")
transition(start_pos_hex, "xX")
epsilon(pos_oct)
}
// Binary integers.
state(start_pos_bin) {
epsilon(pos_bin)
}
term_state(pos_bin) {
transition(pos_bin, "01", add_ascii<2>(result, ch), pec::integer_overflow)
}
// Octal integers.
state(start_pos_oct) {
epsilon(pos_oct)
}
term_state(pos_oct) {
transition(pos_oct, octal_chars, add_ascii<8>(result, ch),
pec::integer_overflow)
}
// Hexal integers.
state(start_pos_hex) {
epsilon(pos_hex)
}
term_state(pos_hex) {
transition(pos_hex, hexadecimal_chars, add_ascii<16>(result, ch),
pec::integer_overflow)
}
// Reads the integer part of the mantissa or a positive decimal integer.
term_state(pos_dec) {
transition(pos_dec, decimal_chars, add_ascii<10>(result, ch),
pec::integer_overflow)
}
fin();
// clang-format on
}
} // namespace parser
} // namespace detail
} // namespace caf
#include "caf/detail/parser/fsm_undef.hpp"
CAF_POP_WARNINGS
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#define CAF_SUITE read_signed_integer
#include "caf/detail/parser/read_signed_integer.hpp"
#include "caf/test/dsl.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/string_view.hpp"
using namespace caf;
namespace {
template <class T>
struct signed_integer_consumer {
using value_type = T;
void value(T y) {
x = y;
}
T x;
};
template <class T>
optional<T> read(string_view str) {
signed_integer_consumer<T> consumer;
detail::parser::state<string_view::iterator> ps{str.begin(), str.end()};
detail::parser::read_signed_integer(ps, consumer);
if (ps.code != pec::success)
return none;
return consumer.x;
}
template <class T>
bool underflow(string_view str) {
signed_integer_consumer<T> consumer;
detail::parser::state<string_view::iterator> ps{str.begin(), str.end()};
detail::parser::read_signed_integer(ps, consumer);
return ps.code == pec::integer_underflow;
}
template <class T>
bool overflow(string_view str) {
signed_integer_consumer<T> consumer;
detail::parser::state<string_view::iterator> ps{str.begin(), str.end()};
detail::parser::read_signed_integer(ps, consumer);
return ps.code == pec::integer_overflow;
}
template <class T>
T min_val() {
return std::numeric_limits<T>::min();
}
template <class T>
T max_val() {
return std::numeric_limits<T>::max();
}
} // namespace
#define ZERO_VALUE(type, literal) \
CAF_CHECK_EQUAL(read<type>(#literal), type(0));
#define MAX_VALUE(type, literal) \
CAF_CHECK_EQUAL(read<type>(#literal), max_val<type>());
#define MIN_VALUE(type, literal) \
CAF_CHECK_EQUAL(read<type>(#literal), min_val<type>());
#ifdef OVERFLOW
# undef OVERFLOW
#endif // OVERFLOW
#define OVERFLOW(type, literal) CAF_CHECK(overflow<type>(#literal));
#ifdef UNDERFLOW
# undef UNDERFLOW
#endif // UNDERFLOW
#define UNDERFLOW(type, literal) CAF_CHECK(underflow<type>(#literal));
CAF_TEST(read zeros) {
ZERO_VALUE(int8_t, 0);
ZERO_VALUE(int8_t, 00);
ZERO_VALUE(int8_t, 0x0);
ZERO_VALUE(int8_t, 0X00);
ZERO_VALUE(int8_t, 0b0);
ZERO_VALUE(int8_t, 0B00);
ZERO_VALUE(int8_t, +0);
ZERO_VALUE(int8_t, +00);
ZERO_VALUE(int8_t, +0x0);
ZERO_VALUE(int8_t, +0X00);
ZERO_VALUE(int8_t, +0b0);
ZERO_VALUE(int8_t, +0B00);
ZERO_VALUE(int8_t, -0);
ZERO_VALUE(int8_t, -00);
ZERO_VALUE(int8_t, -0x0);
ZERO_VALUE(int8_t, -0X00);
ZERO_VALUE(int8_t, -0b0);
ZERO_VALUE(int8_t, -0B00);
}
CAF_TEST(minimal value) {
MIN_VALUE(int8_t, -0b10000000);
MIN_VALUE(int8_t, -0200);
MIN_VALUE(int8_t, -128);
MIN_VALUE(int8_t, -0x80);
UNDERFLOW(int8_t, -0b10000001);
UNDERFLOW(int8_t, -0201);
UNDERFLOW(int8_t, -129);
UNDERFLOW(int8_t, -0x81);
MIN_VALUE(int16_t, -0b1000000000000000);
MIN_VALUE(int16_t, -0100000);
MIN_VALUE(int16_t, -32768);
MIN_VALUE(int16_t, -0x8000);
UNDERFLOW(int16_t, -0b1000000000000001);
UNDERFLOW(int16_t, -0100001);
UNDERFLOW(int16_t, -32769);
UNDERFLOW(int16_t, -0x8001);
MIN_VALUE(int32_t, -0b10000000000000000000000000000000);
MIN_VALUE(int32_t, -020000000000);
MIN_VALUE(int32_t, -2147483648);
MIN_VALUE(int32_t, -0x80000000);
UNDERFLOW(int32_t, -0b10000000000000000000000000000001);
UNDERFLOW(int32_t, -020000000001);
UNDERFLOW(int32_t, -2147483649);
UNDERFLOW(int32_t, -0x80000001);
MIN_VALUE(int64_t, -01000000000000000000000);
MIN_VALUE(int64_t, -9223372036854775808);
MIN_VALUE(int64_t, -0x8000000000000000);
UNDERFLOW(int64_t, -01000000000000000000001);
UNDERFLOW(int64_t, -9223372036854775809);
UNDERFLOW(int64_t, -0x8000000000000001);
}
CAF_TEST(maximal value) {
MAX_VALUE(int8_t, 0b1111111);
MAX_VALUE(int8_t, 0177);
MAX_VALUE(int8_t, 127);
MAX_VALUE(int8_t, 0x7F);
OVERFLOW(int8_t, 0b10000000);
OVERFLOW(int8_t, 0200);
OVERFLOW(int8_t, 128);
OVERFLOW(int8_t, 0x80);
MAX_VALUE(int16_t, 0b111111111111111);
MAX_VALUE(int16_t, 077777);
MAX_VALUE(int16_t, 32767);
MAX_VALUE(int16_t, 0x7FFF);
OVERFLOW(int16_t, 0b1000000000000000);
OVERFLOW(int16_t, 0100000);
OVERFLOW(int16_t, 32768);
OVERFLOW(int16_t, 0x8000);
MAX_VALUE(int32_t, 0b1111111111111111111111111111111);
MAX_VALUE(int32_t, 017777777777);
MAX_VALUE(int32_t, 2147483647);
MAX_VALUE(int32_t, 0x7FFFFFFF);
OVERFLOW(int32_t, 0b10000000000000000000000000000000);
OVERFLOW(int32_t, 020000000000);
OVERFLOW(int32_t, 2147483648);
OVERFLOW(int32_t, 0x80000000);
MAX_VALUE(int64_t,
0b111111111111111111111111111111111111111111111111111111111111111);
MAX_VALUE(int64_t, 0777777777777777777777);
MAX_VALUE(int64_t, 9223372036854775807);
MAX_VALUE(int64_t, 0x7FFFFFFFFFFFFFFF);
OVERFLOW(int64_t,
0b1000000000000000000000000000000000000000000000000000000000000000);
OVERFLOW(int64_t, 01000000000000000000000);
OVERFLOW(int64_t, 9223372036854775808);
OVERFLOW(int64_t, 0x8000000000000000);
}
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#define CAF_SUITE read_unsigned_integer
#include "caf/detail/parser/read_unsigned_integer.hpp"
#include "caf/test/dsl.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/string_view.hpp"
using namespace caf;
namespace {
template <class T>
struct unsigned_integer_consumer {
using value_type = T;
void value(T y) {
x = y;
}
T x;
};
template <class T>
optional<T> read(string_view str) {
unsigned_integer_consumer<T> consumer;
detail::parser::state<string_view::iterator> ps{str.begin(), str.end()};
detail::parser::read_unsigned_integer(ps, consumer);
if (ps.code != pec::success)
return none;
return consumer.x;
}
template <class T>
bool overflow(string_view str) {
unsigned_integer_consumer<T> consumer;
detail::parser::state<string_view::iterator> ps{str.begin(), str.end()};
detail::parser::read_unsigned_integer(ps, consumer);
return ps.code == pec::integer_overflow;
}
template <class T>
T max_val() {
return std::numeric_limits<T>::max();
}
} // namespace
#define ZERO_VALUE(type, literal) \
CAF_CHECK_EQUAL(read<type>(#literal), type(0));
#define MAX_VALUE(type, literal) \
CAF_CHECK_EQUAL(read<type>(#literal), max_val<type>());
#ifdef OVERFLOW
# undef OVERFLOW
#endif // OVERFLOW
#define OVERFLOW(type, literal) CAF_CHECK(overflow<type>(#literal));
CAF_TEST(read zeros) {
ZERO_VALUE(uint8_t, 0);
ZERO_VALUE(uint8_t, 00);
ZERO_VALUE(uint8_t, 0x0);
ZERO_VALUE(uint8_t, 0X00);
ZERO_VALUE(uint8_t, 0b0);
ZERO_VALUE(uint8_t, 0B00);
ZERO_VALUE(uint8_t, +0);
ZERO_VALUE(uint8_t, +00);
ZERO_VALUE(uint8_t, +0x0);
ZERO_VALUE(uint8_t, +0X00);
ZERO_VALUE(uint8_t, +0b0);
ZERO_VALUE(uint8_t, +0B00);
}
CAF_TEST(maximal value) {
MAX_VALUE(uint8_t, 0b11111111);
MAX_VALUE(uint8_t, 0377);
MAX_VALUE(uint8_t, 255);
MAX_VALUE(uint8_t, 0xFF);
OVERFLOW(uint8_t, 0b100000000);
OVERFLOW(uint8_t, 0400);
OVERFLOW(uint8_t, 256);
OVERFLOW(uint8_t, 0x100);
MAX_VALUE(uint16_t, 0b1111111111111111);
MAX_VALUE(uint16_t, 0177777);
MAX_VALUE(uint16_t, 65535);
MAX_VALUE(uint16_t, 0xFFFF);
OVERFLOW(uint16_t, 0b10000000000000000);
OVERFLOW(uint16_t, 0200000);
OVERFLOW(uint16_t, 65536);
OVERFLOW(uint16_t, 0x10000);
MAX_VALUE(uint32_t, 0b11111111111111111111111111111111);
MAX_VALUE(uint32_t, 037777777777);
MAX_VALUE(uint32_t, 4294967295);
MAX_VALUE(uint32_t, 0xFFFFFFFF);
OVERFLOW(uint32_t, 0b100000000000000000000000000000000);
OVERFLOW(uint32_t, 040000000000);
OVERFLOW(uint32_t, 4294967296);
OVERFLOW(uint32_t, 0x100000000);
MAX_VALUE(uint64_t,
0b1111111111111111111111111111111111111111111111111111111111111111);
MAX_VALUE(uint64_t, 01777777777777777777777);
MAX_VALUE(uint64_t, 18446744073709551615);
MAX_VALUE(uint64_t, 0xFFFFFFFFFFFFFFFF);
OVERFLOW(uint64_t,
0b10000000000000000000000000000000000000000000000000000000000000000);
OVERFLOW(uint64_t, 02000000000000000000000);
OVERFLOW(uint64_t, 18446744073709551616);
OVERFLOW(uint64_t, 0x10000000000000000);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment