Commit 595a8e30 authored by Dominik Charousset's avatar Dominik Charousset

Add field base type to reduce code duplication

parent 11c4eaca
...@@ -33,12 +33,6 @@ public: ...@@ -33,12 +33,6 @@ public:
// -- observers -------------------------------------------------------------- // -- observers --------------------------------------------------------------
/// Checks whether `x` matches the type of this field.
virtual bool type_check(const config_value& x) const noexcept = 0;
/// Returns whether this field in `object` contains valid data.
virtual bool valid(const Object& object) const noexcept = 0;
/// Returns whether this field has a default value. /// Returns whether this field has a default value.
virtual bool has_default() const noexcept = 0; virtual bool has_default() const noexcept = 0;
...@@ -48,11 +42,13 @@ public: ...@@ -48,11 +42,13 @@ public:
/// Returns the value of this field in `object` as config value. /// Returns the value of this field in `object` as config value.
virtual config_value get(const Object& object) const = 0; virtual config_value get(const Object& object) const = 0;
/// Returns whether calling `set` with `x` would succeed.
virtual bool valid_input(const config_value& x) const = 0;
// -- modifiers -------------------------------------------------------------- // -- modifiers --------------------------------------------------------------
/// Sets this field in `object` to `x`. /// Sets this field in `object` to `x`.
/// @pre `can_set(x)` virtual bool set(Object& object, const config_value& x) const = 0;
virtual void set(Object& object, const config_value& x) const = 0;
/// Restores the default value for this field in `object`. /// Restores the default value for this field in `object`.
/// @pre `has_default()` /// @pre `has_default()`
......
...@@ -48,17 +48,19 @@ struct config_value_object_access { ...@@ -48,17 +48,19 @@ struct config_value_object_access {
if (!dict) if (!dict)
return false; return false;
for (auto field : Trait::fields()) { for (auto field : Trait::fields()) {
auto value = caf::get_if(dict, field->name()); if (auto value = caf::get_if(dict, field->name())) {
if (!value) { if (dst) {
if (!field->set(*dst, *value))
return false;
} else {
if (!field->valid_input(*value))
return false;
}
} else {
if (!field->has_default()) if (!field->has_default())
return false; return false;
if (dst) if (dst)
field->set_default(*dst); field->set_default(*dst);
} else if (field->type_check(*value)) {
if (dst)
field->set(*dst, *value);
} else {
return false;
} }
} }
return true; return true;
...@@ -156,10 +158,6 @@ struct config_value_object_access { ...@@ -156,10 +158,6 @@ struct config_value_object_access {
ps.code = pec::unexpected_eof; ps.code = pec::unexpected_eof;
return; return;
} }
if (!fptr->valid(x)) {
ps.code = pec::illegal_argument;
return;
}
result[fptr->name()] = fptr->get(x); result[fptr->name()] = fptr->get(x);
} while (ps.consume(',')); } while (ps.consume(','));
if (!ps.consume('}')) { if (!ps.consume('}')) {
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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 "caf/config_value.hpp"
#include "caf/config_value_field.hpp"
#include "caf/detail/dispatch_parse_cli.hpp"
#include "caf/optional.hpp"
namespace caf {
namespace detail {
template <class Object, class Value>
class config_value_field_base : public config_value_field<Object> {
public:
using super = config_value_field<Object>;
using object_type = typename super::object_type;
using value_type = Value;
using predicate_type = bool (*)(const value_type&);
config_value_field_base(string_view name, optional<value_type> default_value,
predicate_type predicate)
: name_(name),
default_value_(std::move(default_value)),
predicate_(predicate) {
// nop
}
config_value_field_base(config_value_field_base&&) = default;
bool has_default() const noexcept override {
return static_cast<bool>(default_value_);
}
string_view name() const noexcept override {
return name_;
}
config_value get(const object_type& object) const override {
using access = caf::select_config_value_access_t<value_type>;
return config_value{access::convert(get_value(object))};
}
bool valid_input(const config_value& x) const override {
if (!predicate_)
return holds_alternative<value_type>(x);
if (auto value = get_if<value_type>(&x))
return predicate_(*value);
return false;
}
bool set(object_type& x, const config_value& y) const override {
if (auto value = get_if<value_type>(&y)) {
if (predicate_ && !predicate_(*value))
return false;
set_value(x, move_if_optional(value));
return true;
}
return false;
}
void set_default(object_type& x) const override {
set_value(x, *default_value_);
}
void parse_cli(string_parser_state& ps, object_type& x,
const char* char_blacklist) const override {
value_type tmp;
dispatch_parse_cli(ps, tmp, char_blacklist);
if (ps.code <= pec::trailing_character) {
if (predicate_ && !predicate_(tmp))
ps.code = pec::illegal_argument;
else
set_value(x, std::move(tmp));
}
}
virtual const value_type& get_value(const object_type& object) const = 0;
virtual void set_value(object_type& object, value_type value) const = 0;
protected:
string_view name_;
optional<value_type> default_value_;
predicate_type predicate_;
};
} // namespace detail
} // namespace caf
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "caf/config_value.hpp" #include "caf/config_value.hpp"
#include "caf/config_value_field.hpp" #include "caf/config_value_field.hpp"
#include "caf/detail/config_value_field_base.hpp"
#include "caf/detail/dispatch_parse_cli.hpp" #include "caf/detail/dispatch_parse_cli.hpp"
#include "caf/detail/parse.hpp" #include "caf/detail/parse.hpp"
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
...@@ -38,157 +39,110 @@ class config_value_field_impl; ...@@ -38,157 +39,110 @@ class config_value_field_impl;
// A config value with direct access to a field via member object pointer. // A config value with direct access to a field via member object pointer.
template <class Value, class Object> template <class Value, class Object>
class config_value_field_impl<Value Object::*> class config_value_field_impl<Value Object::*>
: public config_value_field<Object> { : public config_value_field_base<Object, Value> {
public: public:
using super = config_value_field_base<Object, Value>;
using member_pointer = Value Object::*; using member_pointer = Value Object::*;
using object_type = Object; using object_type = Object;
using value_type = Value; using value_type = Value;
using predicate_pointer = bool (*)(const value_type&); using predicate_type = bool (*)(const value_type&);
constexpr config_value_field_impl(string_view name, member_pointer ptr, constexpr config_value_field_impl(string_view name, member_pointer ptr,
optional<value_type> default_value = none, optional<value_type> default_value = none,
predicate_pointer predicate = nullptr) predicate_type predicate = nullptr)
: name_(name), : super(name, std::move(default_value), predicate), ptr_(ptr) {
ptr_(ptr),
default_value_(std::move(default_value)),
predicate_(predicate) {
// nop // nop
} }
constexpr config_value_field_impl(config_value_field_impl&&) = default; constexpr config_value_field_impl(config_value_field_impl&&) = default;
bool type_check(const config_value& x) const noexcept override { const value_type& get_value(const object_type& x) const override {
return holds_alternative<value_type>(x); return x.*ptr_;
}
bool valid(const object_type& x) const noexcept override {
return predicate_ ? predicate_(x.*ptr_) : true;
}
void set(object_type& x, const config_value& y) const override {
x.*ptr_ = caf::get<value_type>(y);
}
config_value get(const object_type& x) const override {
using access = select_config_value_access_t<value_type>;
return config_value{access::convert(x.*ptr_)};
} }
void parse_cli(string_parser_state& ps, object_type& x, void set_value(object_type& x, value_type y) const override {
const char* char_blacklist) const override { x.*ptr_ = std::move(y);
detail::dispatch_parse_cli(ps, x.*ptr_, char_blacklist);
}
string_view name() const noexcept override {
return name_;
}
bool has_default() const noexcept override {
return static_cast<bool>(default_value_);
}
void set_default(object_type& x) const override {
x.*ptr_ = *default_value_;
} }
private: private:
string_view name_;
member_pointer ptr_; member_pointer ptr_;
optional<value_type> default_value_;
predicate_pointer predicate_;
}; };
template <class Get> template <class Get>
struct config_value_field_base { struct config_value_field_trait {
using trait = get_callable_trait_t<Get>; using trait = get_callable_trait_t<Get>;
static_assert(trait::num_args == 1, static_assert(trait::num_args == 1,
"Get must take exactly one argument (the object)"); "Get must take exactly one argument (the object)");
using arg_type = tl_head_t<typename trait::arg_types>; using get_argument_type = tl_head_t<typename trait::arg_types>;
using value_type = decay_t<typename trait::result_type>; using object_type = decay_t<get_argument_type>;
using type = config_value_field<decay_t<arg_type>>; using get_result_type = typename trait::result_type;
};
template <class Get> using value_type = decay_t<get_result_type>;
using config_value_field_base_t = typename config_value_field_base<Get>::type; };
// A config value with access to a field via getter and setter. // A config value with access to a field via getter and setter.
template <class Get, class Set> template <class Get, class Set>
class config_value_field_impl<std::pair<Get, Set>> class config_value_field_impl<std::pair<Get, Set>>
: public config_value_field_base_t<Get> {
: public config_value_field_base<
typename config_value_field_trait<Get>::object_type,
typename config_value_field_trait<Get>::value_type> {
public: public:
using super = config_value_field_base_t<Get>; using trait = config_value_field_trait<Get>;
using object_type = typename trait::object_type;
using object_type = typename super::object_type; using get_result_type = typename trait::get_result_type;
using get_trait = get_callable_trait_t<Get>; using value_type = typename trait::value_type;
using value_type = decay_t<typename get_trait::result_type>; using predicate_type = bool (*)(const value_type&);
using predicate_pointer = bool (*)(const value_type&); using super = config_value_field_base<object_type, value_type>;
constexpr config_value_field_impl(string_view name, Get getter, Set setter, constexpr config_value_field_impl(string_view name, Get getter, Set setter,
optional<value_type> default_value = none, optional<value_type> default_value = none,
predicate_pointer predicate = nullptr) predicate_type predicate = nullptr)
: name_(name), : super(name, std::move(default_value), predicate),
get_(std::move(getter)), get_(std::move(getter)),
set_(std::move(setter)), set_(std::move(setter)) {
default_value_(std::move(default_value)),
predicate_(predicate) {
// nop // nop
} }
constexpr config_value_field_impl(config_value_field_impl&&) = default; constexpr config_value_field_impl(config_value_field_impl&&) = default;
bool type_check(const config_value& x) const noexcept override { const value_type& get_value(const object_type& x) const override {
return holds_alternative<value_type>(x); bool_token<std::is_lvalue_reference<get_result_type>::value> token;
} return get_value_impl(x, token);
void set(object_type& x, const config_value& y) const override {
set_(x, caf::get<value_type>(y));
}
config_value get(const object_type& x) const override {
using access = select_config_value_access_t<value_type>;
return config_value{access::convert(get_(x))};
}
bool valid(const object_type& x) const noexcept override {
return predicate_ ? predicate_(get_(x)) : true;
} }
void parse_cli(string_parser_state& ps, object_type& x, void set_value(object_type& x, value_type y) const override {
const char* char_blacklist) const override { set_(x, std::move(y));
value_type tmp;
detail::dispatch_parse_cli(ps, tmp, char_blacklist);
if (ps.code <= pec::trailing_character)
set_(x, std::move(tmp));
} }
string_view name() const noexcept override { private:
return name_; template <class O>
} const value_type& get_value_impl(const O& x, std::true_type) const {
return get_(x);
bool has_default() const noexcept override {
return static_cast<bool>(default_value_);
} }
void set_default(object_type& x) const override { template <class O>
set_(x, *default_value_); const value_type& get_value_impl(const O& x, std::false_type) const {
dummy_ = get_(x);
return dummy_;
} }
private:
string_view name_;
Get get_; Get get_;
Set set_; Set set_;
optional<value_type> default_value_; mutable value_type dummy_;
predicate_pointer predicate_;
}; };
} // namespace detail } // namespace detail
......
...@@ -130,15 +130,12 @@ struct fixture { ...@@ -130,15 +130,12 @@ struct fixture {
foobar x; foobar x;
CAF_CHECK_EQUAL(foo_field.name(), "foo"); CAF_CHECK_EQUAL(foo_field.name(), "foo");
CAF_REQUIRE(foo_field.has_default()); CAF_REQUIRE(foo_field.has_default());
CAF_CHECK(foo_field.valid(x));
CAF_CHECK_EQUAL(foo_field.get(x), config_value(0)); CAF_CHECK_EQUAL(foo_field.get(x), config_value(0));
foo_field.set_default(x); foo_field.set_default(x);
CAF_CHECK_EQUAL(foo_field.get(x), config_value(42)); CAF_CHECK_EQUAL(foo_field.get(x), config_value(42));
CAF_CHECK(!foo_field.type_check(config_value(1.))); CAF_CHECK(!foo_field.valid_input(config_value(1.)));
CAF_CHECK(foo_field.type_check(config_value(-1))); CAF_CHECK(!foo_field.valid_input(config_value(-1)));
foo_field.set(x, config_value(-1)); CAF_CHECK(!foo_field.set(x, config_value(-1)));
CAF_CHECK_EQUAL(foo_field.get(x), config_value(-1));
CAF_CHECK(!foo_field.valid(x));
string_view input = "123"; string_view input = "123";
string_parser_state ps{input.begin(), input.end()}; string_parser_state ps{input.begin(), input.end()};
foo_field.parse_cli(ps, x); foo_field.parse_cli(ps, x);
......
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