Commit f36bc529 authored by Dominik Charousset's avatar Dominik Charousset

Use config_value_access to obtain type names

parent 2ee64506
......@@ -238,39 +238,43 @@ struct config_value_access_unspecialized {};
template <class T>
struct config_value_access : config_value_access_unspecialized {};
#define CAF_DEFAULT_CONFIG_VALUE_ACCESS(type) \
#define CAF_DEFAULT_CONFIG_VALUE_ACCESS(type, name) \
template <> \
struct config_value_access<type> : default_config_value_access<type> {}
struct config_value_access<type> : default_config_value_access<type> { \
static std::string type_name() { \
return name; \
} \
}
CAF_DEFAULT_CONFIG_VALUE_ACCESS(bool);
CAF_DEFAULT_CONFIG_VALUE_ACCESS(double);
CAF_DEFAULT_CONFIG_VALUE_ACCESS(atom_value);
CAF_DEFAULT_CONFIG_VALUE_ACCESS(timespan);
CAF_DEFAULT_CONFIG_VALUE_ACCESS(std::string);
CAF_DEFAULT_CONFIG_VALUE_ACCESS(config_value::list);
CAF_DEFAULT_CONFIG_VALUE_ACCESS(config_value::dictionary);
CAF_DEFAULT_CONFIG_VALUE_ACCESS(bool, "boolean");
CAF_DEFAULT_CONFIG_VALUE_ACCESS(double, "real64");
CAF_DEFAULT_CONFIG_VALUE_ACCESS(atom_value, "atom");
CAF_DEFAULT_CONFIG_VALUE_ACCESS(timespan, "timespan");
CAF_DEFAULT_CONFIG_VALUE_ACCESS(std::string, "string");
CAF_DEFAULT_CONFIG_VALUE_ACCESS(config_value::list, "list");
CAF_DEFAULT_CONFIG_VALUE_ACCESS(config_value::dictionary, "dictionary");
#undef CAF_DEFAULT_CONFIG_VALUE_ACCESS
enum class select_config_value_hint {
is_custom,
is_integral,
is_list,
is_map,
is_list,
is_custom,
is_missing,
};
template <class T>
constexpr select_config_value_hint select_config_value_oracle() {
return !std::is_base_of<config_value_access_unspecialized,
config_value_access<T>>::value
? select_config_value_hint::is_custom
: (std::is_integral<T>::value
return std::is_integral<T>::value
? select_config_value_hint::is_integral
: (detail::is_map_like<T>::value
? select_config_value_hint::is_map
: (detail::is_list_like<T>::value
? select_config_value_hint::is_list
: (!std::is_base_of<config_value_access_unspecialized,
config_value_access<T>>::value
? select_config_value_hint::is_custom
: select_config_value_hint::is_missing)));
}
......@@ -362,13 +366,25 @@ struct sum_type_access<config_value> {
template <class T>
struct select_config_value_access<T, select_config_value_hint::is_integral> {
struct type {
using integer_type = config_value::integer;
static std::string type_name() {
std::string result;
if (std::is_signed<T>::value)
result = "int";
else
result = "uint";
result += std::to_string(sizeof(T) * 8);
return result;
}
static bool is(const config_value& x) {
auto ptr = caf::get_if<typename config_value::integer>(x.get_data_ptr());
auto ptr = caf::get_if<integer_type>(x.get_data_ptr());
return ptr != nullptr && detail::bounds_checker<T>::check(*ptr);
}
static optional<T> get_if(const config_value* x) {
auto ptr = caf::get_if<typename config_value::integer>(x->get_data_ptr());
auto ptr = caf::get_if<integer_type>(x->get_data_ptr());
if (ptr != nullptr && detail::bounds_checker<T>::check(*ptr))
return static_cast<T>(*ptr);
return none;
......@@ -390,13 +406,19 @@ struct select_config_value_access<T, select_config_value_hint::is_list> {
using value_type = typename list_type::value_type;
using value_trait = select_config_value_access_t<value_type>;
static std::string type_name() {
return "list of " + value_trait::type_name();
}
static bool is(const config_value& x) {
auto lst = caf::get_if<config_value::list>(&x);
if (lst != nullptr) {
return std::all_of(lst->begin(), lst->end(), [](const config_value& y) {
return lst != nullptr
&& std::all_of(lst->begin(), lst->end(),
[](const config_value& y) {
return caf::holds_alternative<value_type>(y);
});
}
return false;
}
......@@ -404,8 +426,7 @@ struct select_config_value_access<T, select_config_value_hint::is_list> {
list_type result;
auto out = std::inserter(result, result.end());
auto extract = [&](const config_value& y) {
auto opt = caf::get_if<value_type>(&y);
if (opt) {
if (auto opt = caf::get_if<value_type>(&y)) {
*out++ = move_if_optional(opt);
return true;
}
......@@ -434,14 +455,22 @@ struct select_config_value_access<T, select_config_value_hint::is_map> {
using mapped_type = typename map_type::mapped_type;
using mapped_trait = select_config_value_access_t<mapped_type>;
static std::string type_name() {
std::string result = "dictionary of ";
auto nested_name = mapped_trait::type_name();
result.insert(result.end(), nested_name.begin(), nested_name.end());
return result;
}
static bool is(const config_value& x) {
using value_type = config_value::dictionary::value_type;
auto dict = caf::get_if<config_value::dictionary>(&x);
if (dict != nullptr) {
return std::all_of(dict->begin(), dict->end(), [](const value_type& y) {
auto is_mapped_type = [](const value_type& y) {
return caf::holds_alternative<mapped_type>(y.second);
});
}
};
if (auto dict = caf::get_if<config_value::dictionary>(&x))
return std::all_of(dict->begin(), dict->end(), is_mapped_type);
return false;
}
......@@ -450,13 +479,13 @@ struct select_config_value_access<T, select_config_value_hint::is_map> {
map_type result;
auto extract = [&](const value_type& y) {
if (auto opt = caf::get_if<mapped_type>(&y.second)) {
result.emplace(y.first, *opt);
result.emplace(y.first, move_if_optional(opt));
return true;
}
return false;
};
auto dict = caf::get_if<config_value::dictionary>(x);
if (dict != nullptr && std::all_of(dict->begin(), dict->end(), extract))
if (auto dict = caf::get_if<config_value::dictionary>(x))
if (std::all_of(dict->begin(), dict->end(), extract))
return result;
return none;
}
......@@ -472,13 +501,16 @@ struct select_config_value_access<T, select_config_value_hint::is_map> {
template <>
struct config_value_access<float> {
static std::string type_name() {
return "real32";
}
static bool is(const config_value& x) {
return holds_alternative<double>(x.get_data());
}
static optional<float> get_if(const config_value* x) {
auto res = caf::get_if<double>(&(x->get_data()));
if (res)
if (auto res = caf::get_if<double>(&(x->get_data())))
return static_cast<float>(*res);
return none;
}
......@@ -495,6 +527,13 @@ template <class... Ts>
struct config_value_access<std::tuple<Ts...>> {
using tuple_type = std::tuple<Ts...>;
static std::string type_name() {
auto result = "tuple[";
rec_name(result, true, detail::int_token<0>(), detail::type_list<Ts...>());
result += ']';
return result;
}
static bool is(const config_value& x) {
if (auto lst = caf::get_if<config_value::list>(&x)) {
if (lst->size() != sizeof...(Ts))
......@@ -523,10 +562,27 @@ struct config_value_access<std::tuple<Ts...>> {
}
private:
template <int Pos>
static void rec_name(std::string&, bool, detail::int_token<Pos>,
detail::type_list<>) {
// nop
}
template <int Pos, class U, class... Us>
static void rec_name(std::string& result, bool is_first,
detail::int_token<Pos>, detail::type_list<U, Us...>) {
if (!is_first)
result += ", ";
using nested = config_value_access<U>;
auto nested_name = nested::type_name();
result.insert(result.end(), nested_name.begin(), nested_name.end());
return rec_name(result, false, detail::int_token<Pos + 1>(),
detail::type_list<Us...>());
}
template <int Pos>
static bool rec_is(const config_value::list&, detail::int_token<Pos>,
detail::type_list<>) {
// End of recursion.
return true;
}
......@@ -541,7 +597,6 @@ private:
template <int Pos>
static bool rec_get(const config_value::list&, tuple_type&,
detail::int_token<Pos>, detail::type_list<>) {
// End of recursion.
return true;
}
......@@ -557,49 +612,6 @@ private:
}
};
/// Implements automagic unboxing of `dictionary<V>` from a homogeneous
/// `config_value::dictionary`.
/// @relates config_value
template <class V>
struct config_value_access<dictionary<V>> {
using map_type = dictionary<V>;
using kvp = std::pair<const std::string, config_value>;
static bool is(const config_value& x) {
auto lst = caf::get_if<config_value::dictionary>(&x);
if (lst != nullptr) {
return std::all_of(lst->begin(), lst->end(), [](const kvp& y) {
return holds_alternative<V>(y.second);
});
}
return false;
}
static optional<map_type> get_if(const config_value* x) {
map_type result;
auto extract = [&](const kvp& y) {
auto opt = caf::get_if<V>(&(y.second));
if (opt) {
result.emplace(y.first, std::move(*opt));
return true;
}
return false;
};
auto lst = caf::get_if<config_value::dictionary>(x);
if (lst != nullptr && std::all_of(lst->begin(), lst->end(), extract))
return result;
return none;
}
static map_type get(const config_value& x) {
auto result = get_if(&x);
if (!result)
CAF_RAISE_ERROR("invalid type found");
return std::move(*result);
}
};
// -- SumType-like access of dictionary values ---------------------------------
/// @relates config_value
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 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 <string>
#include <type_traits>
#include <vector>
#include "caf/dictionary.hpp"
#include "caf/fwd.hpp"
#include "caf/timestamp.hpp"
namespace caf {
namespace detail {
template <size_t Bytes>
struct type_name_builder_int_size;
template <>
struct type_name_builder_int_size<1> {
void operator()(std::string& result) const {
result += "8";
}
};
template <>
struct type_name_builder_int_size<2> {
void operator()(std::string& result) const {
result += "16";
}
};
template <>
struct type_name_builder_int_size<4> {
void operator()(std::string& result) const {
result += "32";
}
};
template <>
struct type_name_builder_int_size<8> {
void operator()(std::string& result) const {
result += "64";
}
};
template <class T, bool IsInteger = std::is_integral<T>::value>
struct type_name_builder;
template <>
struct type_name_builder<bool, true> {
void operator()(std::string& result) const {
result += "boolean";
}
};
#define CAF_TYPE_NAME_BUILDER_NOINT(class_name, pretty_name) \
template <> \
struct type_name_builder<class_name, false> { \
void operator()(std::string& result) const { \
result += pretty_name; \
} \
}
CAF_TYPE_NAME_BUILDER_NOINT(float, "32-bit real");
CAF_TYPE_NAME_BUILDER_NOINT(double, "64-bit real");
CAF_TYPE_NAME_BUILDER_NOINT(timespan, "timespan");
CAF_TYPE_NAME_BUILDER_NOINT(std::string, "string");
CAF_TYPE_NAME_BUILDER_NOINT(atom_value, "atom");
CAF_TYPE_NAME_BUILDER_NOINT(uri, "uri");
#undef CAF_TYPE_NAME_BUILDER
template <class T>
struct type_name_builder<T, true> {
void operator()(std::string& result) const {
// TODO: replace with if constexpr when switching to C++17
if (!std::is_signed<T>::value)
result += 'u';
result += "int";
type_name_builder_int_size<sizeof(T)> g;
g(result);
}
};
template <class T>
struct type_name_builder<std::vector<T>, false> {
void operator()(std::string& result) const {
result += "list of ";
type_name_builder<T> g;
g(result);
}
};
template <class T>
struct type_name_builder<dictionary<T>, false> {
void operator()(std::string& result) const {
result += "dictionary of ";
type_name_builder<T> g;
g(result);
}
};
template <class T>
std::string type_name() {
std::string result;
type_name_builder<T> f;
f(result);
return result;
}
} // namespace detail
} // namespace caf
......@@ -23,7 +23,7 @@
#include "caf/config_option.hpp"
#include "caf/config_value.hpp"
#include "caf/detail/parse.hpp"
#include "caf/detail/type_name.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/error.hpp"
#include "caf/expected.hpp"
#include "caf/fwd.hpp"
......@@ -53,15 +53,15 @@ config_value get_impl(const void* ptr) {
template <class T>
expected<config_value> parse_impl(T* ptr, string_view str) {
if (ptr != nullptr) {
if (auto err = parse(str, *ptr))
return err;
return config_value{*ptr};
}
T tmp;
if (auto err = parse(str, tmp))
return err;
return config_value{std::move(tmp)};
config_value result{std::move(tmp)};
if (!holds_alternative<T>(result))
return pec::type_mismatch;
if (ptr != nullptr)
*ptr = get<T>(result);
return std::move(result);
}
expected<config_value> parse_impl(std::string* ptr, string_view str);
......@@ -73,9 +73,10 @@ expected<config_value> parse_impl_delegate(void* ptr, string_view str) {
template <class T>
config_option::meta_state* option_meta_state_instance() {
using trait = select_config_value_access_t<T>;
static config_option::meta_state obj{check_impl<T>, store_impl<T>,
get_impl<T>, parse_impl_delegate<T>,
detail::type_name<T>()};
trait::type_name()};
return &obj;
}
......
......@@ -24,9 +24,11 @@
#include "caf/optional.hpp"
#define DEFAULT_META(type, parse_fun) \
config_option::meta_state type##_meta_state{ \
default_config_option_check<type>, default_config_option_store<type>, \
get_impl<type>, parse_fun, detail::type_name<type>()};
config_option::meta_state \
type##_meta_state{default_config_option_check<type>, \
default_config_option_store<type>, get_impl<type>, \
parse_fun, \
select_config_value_access_t<type>::type_name()};
using std::string;
......@@ -75,43 +77,34 @@ config_value bool_get_neg(const void* ptr) {
}
meta_state bool_neg_meta{detail::check_impl<bool>, bool_store_neg, bool_get_neg,
nullptr, detail::type_name<bool>()};
nullptr,
select_config_value_access_t<bool>::type_name()};
meta_state us_res_meta{
[](const config_value& x) -> error {
error check_timespan(const config_value& x) {
if (holds_alternative<timespan>(x))
return none;
return make_error(pec::type_mismatch);
},
[](void* ptr, const config_value& x) {
}
template <uint64_t Denominator>
void store_timespan(void* ptr, const config_value& x) {
*static_cast<size_t*>(ptr) = static_cast<size_t>(get<timespan>(x).count())
/ 1000;
},
[](const void* ptr) -> config_value {
/ Denominator;
}
template <uint64_t Denominator>
config_value get_timespan(const void* ptr) {
auto ival = static_cast<int64_t>(*static_cast<const size_t*>(ptr));
timespan val{ival * 1000};
return config_value{val};
},
}
meta_state us_res_meta{check_timespan, store_timespan<1000>, get_timespan<1000>,
nullptr,
detail::type_name<timespan>()
};
select_config_value_access_t<timespan>::type_name()};
meta_state ms_res_meta{[](const config_value& x) -> error {
if (holds_alternative<timespan>(x))
return none;
return make_error(pec::type_mismatch);
},
[](void* ptr, const config_value& x) {
*static_cast<size_t*>(ptr) = static_cast<size_t>(
get<timespan>(x).count() / 1000000);
},
[](const void* ptr) -> config_value {
auto ival = static_cast<int64_t>(
*static_cast<const size_t*>(ptr));
timespan val{ival * 1000000};
return config_value{val};
},
nullptr, detail::type_name<timespan>()};
meta_state ms_res_meta{check_timespan, store_timespan<1000000>,
get_timespan<1000000>, nullptr,
select_config_value_access_t<timespan>::type_name()};
} // namespace
......
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