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