Commit c8c27d13 authored by Dominik Charousset's avatar Dominik Charousset

Allow parsing from iterators and add non-const get

parent 772e4e81
......@@ -100,6 +100,10 @@ public:
// -- parsing ----------------------------------------------------------------
/// Tries to parse a value from `str`.
static expected<config_value> parse(std::string::const_iterator first,
std::string::const_iterator last);
/// Tries to parse a value from `str`.
static expected<config_value> parse(const std::string& str);
......@@ -116,15 +120,6 @@ public:
/// Returns a human-readable type name of the current value.
const char* type_name() const noexcept;
/// Returns a human-readable type name for `T`.
template <class T>
static const char* type_name_of() noexcept {
using namespace detail;
static constexpr auto index = tl_index_of<types, T>::value;
static_assert(index != -1, "T is not a valid config value type");
return type_name_at_index(static_cast<size_t>(index));
}
/// Returns the underlying variant.
inline variant_type& get_data() {
return data_;
......@@ -182,6 +177,13 @@ auto holds_alternative(const config_value& x)
return config_value_access<T>::is(x);
}
/// @relates config_value
template <class T>
auto get_if(config_value* x)
-> decltype(config_value_access<T>::get_if(x)) {
return config_value_access<T>::get_if(x);
}
/// @relates config_value
template <class T>
auto get_if(const config_value* x)
......@@ -189,6 +191,12 @@ auto get_if(const config_value* x)
return config_value_access<T>::get_if(x);
}
/// @relates config_value
template <class T>
auto get(config_value& x) -> decltype(config_value_access<T>::get(x)) {
return config_value_access<T>::get(x);
}
/// @relates config_value
template <class T>
auto get(const config_value& x) -> decltype(config_value_access<T>::get(x)) {
......@@ -216,10 +224,17 @@ struct default_config_value_access {
return holds_alternative<T>(x.get_data());
}
static T* get_if(config_value* x) {
return caf::get_if<T>(&(x->get_data()));
}
static const T* get_if(const config_value* x) {
return caf::get_if<T>(&(x->get_data()));
}
static T& get(config_value& x) {
return caf::get<T>(x.get_data());
}
static const T& get(const config_value& x) {
return caf::get<T>(x.get_data());
}
......
......@@ -158,22 +158,22 @@ struct consumer : abstract_consumer {
} // namespace <anonymous>
expected<config_value> config_value::parse(const std::string& str) {
expected<config_value> config_value::parse(std::string::const_iterator first,
std::string::const_iterator last) {
using namespace detail;
auto i = str.begin();
auto e = str.end();
auto i = first;
// Sanity check.
if (i == e)
if (i == last)
return make_error(parser::ec::unexpected_eof);
// Skip to beginning of the argument.
while (isspace(*i))
if (++i == e)
if (++i == last)
return make_error(parser::ec::unexpected_eof);
// Dispatch to parser.
parser::state<std::string::const_iterator> res;
consumer f;
res.i = i;
res.e = e;
res.e = last;
parser::read_ini_value(res, f);
if (res.code == detail::parser::ec::success)
return std::move(f.result);
......@@ -188,10 +188,14 @@ expected<config_value> config_value::parse(const std::string& str) {
default:
if (isdigit(*i))
return make_error(res.code);
return config_value{str};
return config_value{std::string{first, last}};
}
}
expected<config_value> config_value::parse(const std::string& str) {
return parse(str.begin(), str.end());
}
// -- properties ---------------------------------------------------------------
void config_value::convert_to_list() {
......
......@@ -68,13 +68,18 @@ config_value cfg_lst(Ts&&... xs) {
return config_value{std::move(lst)};
}
// TODO: switch to std::operator""s when switching to C++14
std::string operator"" _s(const char* str, size_t size) {
return std::string(str, size);
}
} // namespace <anonymous>
CAF_TEST(default_constructed) {
config_value x;
CAF_CHECK_EQUAL(holds_alternative<int64_t>(x), true);
CAF_CHECK_EQUAL(get<int64_t>(x), 0);
CAF_CHECK_EQUAL(x.type_name(), config_value::type_name_of<int64_t>());
CAF_CHECK_EQUAL(x.type_name(), "integer"_s);
}
CAF_TEST(positive integer) {
......@@ -85,6 +90,9 @@ CAF_TEST(positive integer) {
CAF_CHECK_EQUAL(holds_alternative<uint64_t>(x), true);
CAF_CHECK_EQUAL(get<uint64_t>(x), 4200u);
CAF_CHECK_EQUAL(get_if<uint64_t>(&x), uint64_t{4200});
CAF_CHECK_EQUAL(holds_alternative<int>(x), true);
CAF_CHECK_EQUAL(get<int>(x), 4200);
CAF_CHECK_EQUAL(get_if<int>(&x), 4200);
CAF_CHECK_EQUAL(holds_alternative<int16_t>(x), true);
CAF_CHECK_EQUAL(get<int16_t>(x), 4200);
CAF_CHECK_EQUAL(get_if<int16_t>(&x), int16_t{4200});
......@@ -99,6 +107,9 @@ CAF_TEST(negative integer) {
CAF_CHECK(get_if<int64_t>(&x) != nullptr);
CAF_CHECK_EQUAL(holds_alternative<uint64_t>(x), false);
CAF_CHECK_EQUAL(get_if<uint64_t>(&x), none);
CAF_CHECK_EQUAL(holds_alternative<int>(x), true);
CAF_CHECK_EQUAL(get<int>(x), -1);
CAF_CHECK_EQUAL(get_if<int>(&x), -1);
CAF_CHECK_EQUAL(holds_alternative<int16_t>(x), true);
CAF_CHECK_EQUAL(get<int16_t>(x), -1);
CAF_CHECK_EQUAL(get_if<int16_t>(&x), int16_t{-1});
......@@ -120,7 +131,7 @@ CAF_TEST(list) {
using integer_list = std::vector<int64_t>;
auto xs = make_config_value_list(1, 2, 3);
CAF_CHECK_EQUAL(to_string(xs), "[1, 2, 3]");
CAF_CHECK_EQUAL(xs.type_name(), config_value::type_name_of<list>());
CAF_CHECK_EQUAL(xs.type_name(), "list"_s);
CAF_CHECK_EQUAL(holds_alternative<config_value::list>(xs), true);
CAF_CHECK_EQUAL(holds_alternative<integer_list>(xs), true);
CAF_CHECK_EQUAL(get<integer_list>(xs), integer_list({1, 2, 3}));
......@@ -128,10 +139,10 @@ CAF_TEST(list) {
CAF_TEST(convert_to_list) {
config_value x{int64_t{42}};
CAF_CHECK_EQUAL(x.type_name(), config_value::type_name_of<int64_t>());
CAF_CHECK_EQUAL(x.type_name(), "integer"_s);
CAF_CHECK_EQUAL(to_string(x), "42");
x.convert_to_list();
CAF_CHECK_EQUAL(x.type_name(), config_value::type_name_of<list>());
CAF_CHECK_EQUAL(x.type_name(), "list"_s);
CAF_CHECK_EQUAL(to_string(x), "[42]");
x.convert_to_list();
CAF_CHECK_EQUAL(to_string(x), "[42]");
......@@ -194,7 +205,8 @@ CAF_TEST(successful parsing) {
auto parse = [](const std::string& str) {
auto x = config_value::parse(str);
if (!x)
CAF_FAIL("cannot parse" << str << ": assumed a result but got an error");
CAF_FAIL("cannot parse " << str << ": assumed a result but error "
<< to_string(x.error()));
return std::move(*x);
};
using di = std::map<string, int>; // Dictionary-of-integers.
......@@ -210,7 +222,8 @@ CAF_TEST(successful parsing) {
CAF_CHECK_EQUAL(get<string>(parse("\"abc\"")), "abc");
CAF_CHECK_EQUAL(get<string>(parse("abc")), "abc");
CAF_CHECK_EQUAL(get<li>(parse("[1, 2, 3]")), li({1, 2, 3}));
CAF_CHECK_EQUAL(get<ls>(parse("[abc, def, ghi]")), ls({"abc", "def", "ghi"}));
CAF_CHECK_EQUAL(get<ls>(parse("[\"abc\", \"def\", \"ghi\"]")),
ls({"abc", "def", "ghi"}));
CAF_CHECK_EQUAL(get<lli>(parse("[[1, 2], [3]]")), lli({li{1, 2}, li{3}}));
CAF_CHECK_EQUAL(get<timespan>(parse("10ms")), milliseconds(10));
CAF_CHECK_EQUAL(get<di>(parse("{a=1,b=2}")), di({{"a", 1}, {"b", 2}}));
......
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