Commit 27bf1b1e authored by Dominik Charousset's avatar Dominik Charousset

Add parse functions for integer types

parent 3237a7d8
......@@ -84,6 +84,7 @@ set(LIBCAF_CORE_SRCS
src/monitorable_actor.cpp
src/node_id.cpp
src/outbound_path.cpp
src/parse.cpp
src/pec.cpp
src/pretty_type_name.cpp
src/private_thread.cpp
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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 <utility>
namespace caf {
namespace detail {
template <class T>
class consumer {
public:
using value_type = T;
explicit consumer(T& x) : x_(x) {
// nop
}
void value(T&& y) {
x_ = std::move(y);
}
private:
T& x_;
};
template <class T>
consumer<T> make_consumer(T& x) {
return consumer<T>{x};
}
} // namespace detail
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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 "caf/detail/parser/state.hpp"
#include "caf/string_view.hpp"
namespace caf {
namespace detail {
using parse_state = parser::state<string_view::iterator>;
// -- signed integer types -----------------------------------------------------
void parse(parse_state& ps, int8_t& x);
void parse(parse_state& ps, int16_t& x);
void parse(parse_state& ps, int32_t& x);
void parse(parse_state& ps, int64_t& x);
// -- unsigned integer types ---------------------------------------------------
void parse(parse_state& ps, uint8_t& x);
void parse(parse_state& ps, uint16_t& x);
void parse(parse_state& ps, uint32_t& x);
void parse(parse_state& ps, uint64_t& x);
// -- floating point types -----------------------------------------------------
void parse(parse_state& ps, float& x);
void parse(parse_state& ps, double& x);
} // namespace detail
} // namespace caf
......@@ -42,8 +42,9 @@ 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;
void read_signed_integer(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
using consumer_type = typename std::decay<Consumer>::type;
using value_type = typename consumer_type::value_type;
static_assert(std::is_integral<value_type>::value
&& std::is_signed<value_type>::value,
"expected a signed integer type");
......@@ -61,17 +62,16 @@ void read_signed_integer(state<Iterator, Sentinel>& ps, Consumer& consumer) {
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)
epsilon(pos_dec, decimal_chars)
}
state(has_minus) {
transition(neg_zero, '0')
epsilon(neg_dec)
epsilon(neg_dec, decimal_chars)
}
// Disambiguate base.
term_state(pos_zero) {
......@@ -86,27 +86,27 @@ void read_signed_integer(state<Iterator, Sentinel>& ps, Consumer& consumer) {
}
// Binary integers.
state(start_pos_bin) {
epsilon(pos_bin)
epsilon(pos_bin, "01")
}
term_state(pos_bin) {
transition(pos_bin, "01", add_ascii<2>(result, ch), pec::integer_overflow)
}
state(start_neg_bin) {
epsilon(neg_bin)
epsilon(neg_bin, "01")
}
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)
epsilon(pos_oct, octal_chars)
}
term_state(pos_oct) {
transition(pos_oct, octal_chars, add_ascii<8>(result, ch),
pec::integer_overflow)
}
state(start_neg_oct) {
epsilon(neg_oct)
epsilon(neg_oct, octal_chars)
}
term_state(neg_oct) {
transition(neg_oct, octal_chars, sub_ascii<8>(result, ch),
......@@ -114,14 +114,14 @@ void read_signed_integer(state<Iterator, Sentinel>& ps, Consumer& consumer) {
}
// Hexal integers.
state(start_pos_hex) {
epsilon(pos_hex)
epsilon(pos_hex, hexadecimal_chars)
}
term_state(pos_hex) {
transition(pos_hex, hexadecimal_chars, add_ascii<16>(result, ch),
pec::integer_overflow)
}
state(start_neg_hex) {
epsilon(neg_hex)
epsilon(neg_hex, hexadecimal_chars)
}
term_state(neg_hex) {
transition(neg_hex, hexadecimal_chars, sub_ascii<16>(result, ch),
......
......@@ -42,8 +42,9 @@ 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;
void read_unsigned_integer(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
using consumer_type = typename std::decay<Consumer>::type;
using value_type = typename consumer_type::value_type;
static_assert(std::is_integral<value_type>::value
&& std::is_unsigned<value_type>::value,
"expected an unsigned integer type");
......@@ -60,46 +61,45 @@ void read_unsigned_integer(state<Iterator, Sentinel>& ps, Consumer& consumer) {
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)
transition(zero, '0')
epsilon(dec, decimal_chars)
}
// Disambiguate base.
term_state(pos_zero) {
transition(start_pos_bin, "bB")
transition(start_pos_hex, "xX")
epsilon(pos_oct)
term_state(zero) {
transition(start_bin, "bB")
transition(start_hex, "xX")
epsilon(oct)
}
// Binary integers.
state(start_pos_bin) {
epsilon(pos_bin)
state(start_bin) {
epsilon(bin, "01")
}
term_state(pos_bin) {
transition(pos_bin, "01", add_ascii<2>(result, ch), pec::integer_overflow)
term_state(bin) {
transition(bin, "01", add_ascii<2>(result, ch), pec::integer_overflow)
}
// Octal integers.
state(start_pos_oct) {
epsilon(pos_oct)
state(start_oct) {
epsilon(oct, octal_chars)
}
term_state(pos_oct) {
transition(pos_oct, octal_chars, add_ascii<8>(result, ch),
term_state(oct) {
transition(oct, octal_chars, add_ascii<8>(result, ch),
pec::integer_overflow)
}
// Hexal integers.
state(start_pos_hex) {
epsilon(pos_hex)
state(start_hex) {
epsilon(hex, hexadecimal_chars)
}
term_state(pos_hex) {
transition(pos_hex, hexadecimal_chars, add_ascii<16>(result, ch),
term_state(hex) {
transition(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),
term_state(dec) {
transition(dec, decimal_chars, add_ascii<10>(result, ch),
pec::integer_overflow)
}
fin();
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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. *
******************************************************************************/
#include "caf/detail/parse.hpp"
#include "caf/detail/consumer.hpp"
#include "caf/detail/parser/read_signed_integer.hpp"
#include "caf/detail/parser/read_unsigned_integer.hpp"
#define PARSE_IMPL(type, parser_name) \
void parse(parse_state& ps, type& x) { \
parser::read_##parser_name(ps, make_consumer(x)); \
}
namespace caf {
namespace detail {
PARSE_IMPL(int8_t, signed_integer)
PARSE_IMPL(int16_t, signed_integer)
PARSE_IMPL(int32_t, signed_integer)
PARSE_IMPL(int64_t, signed_integer)
PARSE_IMPL(uint8_t, unsigned_integer)
PARSE_IMPL(uint16_t, unsigned_integer)
PARSE_IMPL(uint32_t, unsigned_integer)
PARSE_IMPL(uint64_t, unsigned_integer)
} // namespace detail
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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 parse
#include "caf/detail/parse.hpp"
#include "caf/test/dsl.hpp"
#include "caf/expected.hpp"
#include "caf/string_view.hpp"
using namespace caf;
namespace {
template <class T>
expected<T> read(string_view str) {
T result;
detail::parse_state ps{str.begin(), str.end()};
detail::parse(ps, result);
if (ps.code == pec::success)
return result;
return ps.code;
}
} // namespace
#define CHECK_INT(type, value) CAF_CHECK_EQUAL(read<type>(#value), type(value))
#define CHECK_INT_3(type, value, cpp_value) \
CAF_CHECK_EQUAL(read<type>(#value), type(cpp_value))
#define CHECK_INVALID(type, str, code) CAF_CHECK_EQUAL(read<type>(str), code)
CAF_TEST(valid signed integers) {
CHECK_INT(int8_t, -128);
CHECK_INT(int8_t, 127);
CHECK_INT(int8_t, +127);
CHECK_INT(int16_t, -32768);
CHECK_INT(int16_t, 32767);
CHECK_INT(int16_t, +32767);
CHECK_INT(int32_t, -2147483648);
CHECK_INT(int32_t, 2147483647);
CHECK_INT(int32_t, +2147483647);
CHECK_INT(int64_t, -9223372036854775807);
CHECK_INT(int64_t, 9223372036854775807);
CHECK_INT(int64_t, +9223372036854775807);
}
CAF_TEST(valid unsigned integers) {
CHECK_INT(uint8_t, 0);
CHECK_INT(uint8_t, +0);
CHECK_INT(uint8_t, 255);
CHECK_INT(uint8_t, +255);
CHECK_INT(uint16_t, 0);
CHECK_INT(uint16_t, +0);
CHECK_INT(uint16_t, 65535);
CHECK_INT(uint16_t, +65535);
CHECK_INT(uint32_t, 0);
CHECK_INT(uint32_t, +0);
CHECK_INT(uint32_t, 4294967295);
CHECK_INT(uint32_t, +4294967295);
CHECK_INT(uint64_t, 0);
CHECK_INT(uint64_t, +0);
CHECK_INT_3(uint64_t, 18446744073709551615, 18446744073709551615ULL);
CHECK_INT_3(uint64_t, +18446744073709551615, 18446744073709551615ULL);
}
CAF_TEST(invalid unsigned integers) {
CHECK_INVALID(uint8_t, "-1", pec::unexpected_character);
CHECK_INVALID(uint8_t, "++1", pec::unexpected_character);
CHECK_INVALID(uint8_t, "256", pec::integer_overflow);
CHECK_INVALID(uint8_t, "~1", pec::unexpected_character);
CHECK_INVALID(uint8_t, "1!", pec::trailing_character);
}
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