Commit 01cef548 authored by Dominik Charousset's avatar Dominik Charousset

Provide automagic integer access

parent f664eab8
......@@ -27,6 +27,7 @@
#include "caf/atom.hpp"
#include "caf/deep_to_string.hpp"
#include "caf/default_sum_type_access.hpp"
#include "caf/detail/bounds_checker.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/fwd.hpp"
#include "caf/optional.hpp"
......@@ -164,46 +165,45 @@ private:
variant_type data_;
};
/*
/// Enable `holds_alternative`, `get`, `get_if`, and `visit` for `config_value`.
/// @relates config_value
/// @relates SumType
///
template <>
struct sum_type_access<config_value> : default_sum_type_access<config_value> {};
*/
template <class T>
struct config_value_access;
/// @relates config_value
template <class T>
bool holds_alternative(const config_value& x) {
auto holds_alternative(const config_value& x)
-> decltype(config_value_access<T>::is(x)) {
return config_value_access<T>::is(x);
}
/// @relates config_value
template <class T>
auto get_if(const 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(const config_value& x) -> decltype(config_value_access<T>::get(x)) {
return config_value_access<T>::get(x);
}
/// @relates config_value
template <class Visitor>
auto visit(Visitor&& f, config_value& x)
-> decltype(visit(std::forward<Visitor>(f), x.get_data())) {
return visit(std::forward<Visitor>(f), x.get_data());
}
/// @relates config_value
template <class Visitor>
auto visit(Visitor&& f, const config_value& x)
-> decltype(visit(std::forward<Visitor>(f), x.get_data())) {
return visit(std::forward<Visitor>(f), x.get_data());
}
/// @relates config_value_access
template <class T>
struct default_config_value_access {
static bool is(const config_value& x) {
......@@ -233,6 +233,48 @@ CAF_CONFIG_VALUE_DEFAULT_ACCESS(string);
CAF_CONFIG_VALUE_DEFAULT_ACCESS(list);
CAF_CONFIG_VALUE_DEFAULT_ACCESS(dictionary);
/// Checks whether `x` is a `config_value::integer` that can convert to `T`.
/// @relates config_value
template <class T>
detail::enable_if_t<std::is_integral<T>::value
&& !std::is_same<T, typename config_value::integer>::value
&& !std::is_same<T, bool>::value,
bool>
holds_alternative(const config_value& x) {
using cvi = typename config_value::integer;
auto ptr = config_value_access<cvi>::get_if(&x);
return ptr != nullptr && detail::bounds_checker<T>::check(*ptr);
}
/// Tries to convert the value of `x` to `T`.
/// @relates config_value
template <class T>
detail::enable_if_t<std::is_integral<T>::value
&& !std::is_same<T, typename config_value::integer>::value
&& !std::is_same<T, bool>::value,
optional<T>>
get_if(const config_value* x) {
using cvi = typename config_value::integer;
auto ptr = config_value_access<cvi>::get_if(x);
if (ptr != nullptr && detail::bounds_checker<T>::check(*ptr))
return static_cast<T>(*ptr);
return none;
}
/// Converts the value of `x` to `T`.
/// @relates config_value
template <class T>
detail::enable_if_t<std::is_integral<T>::value
&& !std::is_same<T, typename config_value::integer>::value
&& !std::is_same<T, bool>::value,
T>
get(const config_value& x) {
auto res = get_if<T>(&x);
if (res)
return *res;
CAF_RAISE_ERROR("invalid type found");
}
/// Implements automagic unboxing of `std::vector<T>` from a homogeneous
/// `config_value::list`.
/// @relates config_value
......
......@@ -67,37 +67,6 @@ config_value cfg_lst(Ts&&... xs) {
return config_value{std::move(lst)};
}
template <class T>
detail::enable_if_t<std::is_integral<T>::value
&& !std::is_same<T, typename config_value::integer>::value,
optional<T>>
get_if(const config_value* x) {
using cvi = typename config_value::integer;
auto ptr = config_value_access<cvi>::get_if(x);
if (ptr && detail::bounds_checker<T>::check(*ptr))
return static_cast<T>(*ptr);
return none;
}
template <>
optional<uint64_t> get_if<uint64_t>(const config_value* x) {
auto ptr = get_if<typename config_value::integer>(x);
if (ptr && *ptr >= 0)
return static_cast<uint64_t>(*ptr);
return none;
}
template <class T>
detail::enable_if_t<std::is_integral<T>::value
&& !std::is_same<T, typename config_value::integer>::value,
T>
get(const config_value& x) {
auto res = get_if<T>(&x);
if (res)
return *res;
CAF_RAISE_ERROR("invalid type found");
}
} // namespace <anonymous>
CAF_TEST(default_constructed) {
......@@ -109,9 +78,17 @@ CAF_TEST(default_constructed) {
CAF_TEST(integer) {
config_value x{4200};
CAF_CHECK_EQUAL(holds_alternative<int64_t>(x), true);
CAF_CHECK_EQUAL(get<int64_t>(x), 4200);
CAF_CHECK_EQUAL(get<size_t>(x), 4200u);
CAF_CHECK_EQUAL(get_if<uint8_t>(&x), caf::none);
CAF_CHECK(get_if<int64_t>(&x) != nullptr);
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<int16_t>(x), true);
CAF_CHECK_EQUAL(get<int16_t>(x), 4200);
CAF_CHECK_EQUAL(get_if<int16_t>(&x), int16_t{4200});
CAF_CHECK_EQUAL(holds_alternative<int8_t>(x), false);
CAF_CHECK_EQUAL(get_if<int8_t>(&x), caf::none);
}
CAF_TEST(list) {
......
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