Commit 11e0d02b authored by Dominik Charousset's avatar Dominik Charousset

Implement SumType trait for config_value

parent 90026f8e
......@@ -30,6 +30,9 @@
#include "caf/fwd.hpp"
#include "caf/optional.hpp"
#include "caf/string_algorithms.hpp"
#include "caf/sum_type.hpp"
#include "caf/sum_type_access.hpp"
#include "caf/sum_type_token.hpp"
#include "caf/timestamp.hpp"
#include "caf/variant.hpp"
......@@ -122,6 +125,16 @@ public:
return data_;
}
/// Returns a pointer to the underlying variant.
inline variant_type* get_data_ptr() {
return &data_;
}
/// Returns a pointer to the underlying variant.
inline const variant_type* get_data_ptr() const {
return &data_;
}
private:
// -- properties -------------------------------------------------------------
......@@ -158,54 +171,122 @@ private:
variant_type data_;
};
// -- related type aliases -----------------------------------------------------
/// Organizes config values into categories.
/// @relates config_value
using config_value_map = std::map<std::string, config_value::dictionary>;
// -- SumType-like access ------------------------------------------------------
/// @relates config_value
template <class T>
struct config_value_access {
static constexpr bool specialized = false;
struct config_value_access;
/// Delegates to config_value_access for all specialized versions.
template <class T, bool IsIntegral = std::is_integral<T>::value>
struct select_config_value_access {
using type = config_value_access<T>;
};
/// Catches all non-specialized integer types.
template <class T>
struct select_config_value_access<T, true> {
struct type {
static bool is(const config_value& x) {
auto ptr = caf::get_if<typename config_value::integer>(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());
if (ptr != nullptr && detail::bounds_checker<T>::check(*ptr))
return static_cast<T>(*ptr);
return none;
}
static T get(const config_value& x) {
auto res = get_if(&x);
CAF_ASSERT(res != none);
return *res;
}
};
};
/// @relates config_value_access
template <class T>
struct default_config_value_access {
using select_config_value_access_t =
typename select_config_value_access<T>::type;
template <>
struct sum_type_access<config_value> {
using types = typename config_value::types;
using type0 = typename detail::tl_head<types>::type;
static constexpr bool specialized = true;
static bool is(const config_value& x) {
return holds_alternative<T>(x.get_data());
template <class U, int Pos>
static bool is(const config_value& x, sum_type_token<U, Pos> token) {
return x.get_data().is(token.pos);
}
static T* get_if(config_value* x) {
return caf::get_if<T>(&(x->get_data()));
template <class U>
static bool is(const config_value& x, sum_type_token<U, -1>) {
return select_config_value_access_t<U>::is(x);
}
static const T* get_if(const config_value* x) {
return caf::get_if<T>(&(x->get_data()));
template <class U, int Pos>
static U& get(config_value& x, sum_type_token<U, Pos> token) {
return x.get_data().get(token.pos);
}
static T& get(config_value& x) {
return caf::get<T>(x.get_data());
template <class U>
static U get(config_value& x, sum_type_token<U, -1>) {
return select_config_value_access_t<U>::get(x);
}
static const T& get(const config_value& x) {
return caf::get<T>(x.get_data());
template <class U, int Pos>
static const U& get(const config_value& x, sum_type_token<U, Pos> token) {
return x.get_data().get(token.pos);
}
};
#define CAF_CONFIG_VALUE_DEFAULT_ACCESS(subtype) \
template <> \
struct config_value_access<config_value::subtype> \
: default_config_value_access<config_value::subtype> {}
template <class U>
static U get(const config_value& x, sum_type_token<U, -1>) {
return select_config_value_access_t<U>::get(x);
}
CAF_CONFIG_VALUE_DEFAULT_ACCESS(integer);
CAF_CONFIG_VALUE_DEFAULT_ACCESS(boolean);
CAF_CONFIG_VALUE_DEFAULT_ACCESS(real);
CAF_CONFIG_VALUE_DEFAULT_ACCESS(atom);
CAF_CONFIG_VALUE_DEFAULT_ACCESS(timespan);
CAF_CONFIG_VALUE_DEFAULT_ACCESS(string);
CAF_CONFIG_VALUE_DEFAULT_ACCESS(list);
CAF_CONFIG_VALUE_DEFAULT_ACCESS(dictionary);
template <class U, int Pos>
static U* get_if(config_value* x, sum_type_token<U, Pos> token) {
return is(*x, token) ? &get(*x, token) : nullptr;
}
template <class U>
static optional<U> get_if(config_value* x, sum_type_token<U, -1>) {
return select_config_value_access_t<U>::get_if(x);
}
template <class U, int Pos>
static const U* get_if(const config_value* x, sum_type_token<U, Pos> token) {
return is(*x, token) ? &get(*x, token) : nullptr;
}
template <class U>
static optional<U> get_if(const config_value* x, sum_type_token<U, -1>) {
return select_config_value_access_t<U>::get_if(x);
}
template <class Result, class Visitor, class... Ts>
static Result apply(config_value& x, Visitor&& visitor, Ts&&... xs) {
return x.get_data().template apply<Result>(std::forward<Visitor>(visitor),
std::forward<Ts>(xs)...);
}
template <class Result, class Visitor, class... Ts>
static Result apply(const config_value& x, Visitor&& visitor, Ts&&... xs) {
return x.get_data().template apply<Result>(std::forward<Visitor>(visitor),
std::forward<Ts>(xs)...);
}
};
template <>
struct config_value_access<float> {
......@@ -285,7 +366,7 @@ struct config_value_access<std::map<std::string, V>> {
auto lst = caf::get_if<config_value::dictionary>(&x);
if (lst != nullptr) {
return std::all_of(lst->begin(), lst->end(), [](const kvp& x) {
return config_value_access<V>::is(x.second);
return holds_alternative<V>(x.second);
});
}
return false;
......@@ -315,6 +396,8 @@ struct config_value_access<std::map<std::string, V>> {
}
};
// -- SumType-like access of dictionary values ---------------------------------
/// Tries to retrieve the value associated to `name` from `xs`.
/// @relates config_value
template <class T>
......@@ -446,100 +529,6 @@ T get_or(const actor_system_config& cfg, const std::string& name,
std::string get_or(const actor_system_config& cfg, const std::string& name,
const char* default_value);
// -- SumType-like access ------------------------------------------------------
/// Delegates to config_value_access for all specialized versions.
template <class T, bool Specialized = config_value_access<T>::specialized>
struct select_config_value_access {
using type = config_value_access<T>;
};
/// Catches all non-specialized integer types.
template <class T>
struct select_config_value_access<T, false> {
static_assert(std::is_integral<T>::value,
"T must be integral or specialize config_value_access");
struct type {
static bool is(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);
}
static 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;
}
static T get(const config_value& x) {
auto res = get_if(&x);
CAF_ASSERT(res != none);
return *res;
}
};
};
template <class T>
using select_config_value_access_t =
typename select_config_value_access<T>::type;
/// @relates config_value
template <class T>
bool holds_alternative(const config_value& x) {
return select_config_value_access_t<T>::is(x);
}
/// @relates config_value
template <class T>
typename std::conditional<detail::is_primitive_config_value<T>::value, const T*,
optional<T>>::type
get_if(const config_value* x) {
return select_config_value_access_t<T>::get_if(x);
}
/// @relates config_value
template <class T>
typename std::conditional<detail::is_primitive_config_value<T>::value, T*,
optional<T>>::type
get_if(config_value* x) {
return select_config_value_access_t<T>::get_if(x);
}
/// @relates config_value
template <class T>
typename std::conditional<detail::is_primitive_config_value<T>::value, const T&,
T>::type
get(const config_value& x) {
return select_config_value_access_t<T>::get(x);
}
/// @relates config_value
template <class T>
typename std::conditional<detail::is_primitive_config_value<T>::value, T&,
T>::type
get(config_value& x) {
return select_config_value_access_t<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
bool operator<(const config_value& x, const config_value& y);
......
......@@ -23,6 +23,7 @@
#include <utility>
#include "caf/detail/type_list.hpp"
#include "caf/sum_type_token.hpp"
namespace caf {
......@@ -36,21 +37,29 @@ struct default_sum_type_access {
static constexpr bool specialized = true;
template <int Pos>
static bool is(const T& x, std::integral_constant<int, Pos> token) {
return x.get_data().is(token);
template <class U, int Pos>
static bool is(const T& x, sum_type_token<U, Pos> token) {
return x.get_data().is(token.pos);
}
template <int Pos>
static typename detail::tl_at<types, Pos>::type&
get(T& x, std::integral_constant<int, Pos> token) {
return x.get_data().get(token);
template <class U, int Pos>
static U& get(T& x, sum_type_token<U, Pos> token) {
return x.get_data().get(token.pos);
}
template <int Pos>
static const typename detail::tl_at<types, Pos>::type&
get(const T& x, std::integral_constant<int, Pos> token) {
return x.get_data().get(token);
template <class U, int Pos>
static const U& get(const T& x, sum_type_token<U, Pos> token) {
return x.get_data().get(token.pos);
}
template <class U, int Pos>
static U* get_if(T* x, sum_type_token<U, Pos> token) {
return is(*x, token) ? &get(*x, token) : nullptr;
}
template <class U, int Pos>
static const U* get_if(const T* x, sum_type_token<U, Pos> token) {
return is(*x, token) ? &get(*x, token) : nullptr;
}
template <class Result, class Visitor, class... Ts>
......
......@@ -159,31 +159,6 @@ enum class atom_value : uint64_t;
using actor_id = uint64_t;
using stream_slot = uint16_t;
// -- free functions related to forwarded types --------------------------------
template <class T>
bool holds_alternative(const config_value&);
template <class T>
typename std::conditional<detail::is_primitive_config_value<T>::value, const T*,
optional<T>>::type
get_if(const config_value*);
template <class T>
typename std::conditional<detail::is_primitive_config_value<T>::value, T*,
optional<T>>::type
get_if(config_value*);
template <class T>
typename std::conditional<detail::is_primitive_config_value<T>::value, const T&,
T>::type
get(const config_value&);
template <class T>
typename std::conditional<detail::is_primitive_config_value<T>::value, T&,
T>::type
get(config_value&);
// -- functions ----------------------------------------------------------------
/// @relates actor_system_config
......
......@@ -21,6 +21,7 @@
#include <memory>
#include "caf/config_option.hpp"
#include "caf/config_value.hpp"
#include "caf/detail/type_name.hpp"
#include "caf/error.hpp"
#include "caf/fwd.hpp"
......
......@@ -21,6 +21,7 @@
#include "caf/detail/type_list.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/sum_type_access.hpp"
#include "caf/sum_type_token.hpp"
namespace caf {
......@@ -40,59 +41,57 @@ constexpr bool SumTypes() {
return tl_forall<types, has_sum_type_access>::value;
}
template <class Trait, class T, bool = Trait::specialized>
struct sum_type_index {
static constexpr int value = -1;
};
template <class Trait, class T>
struct sum_type_index<Trait, T, true> {
static constexpr int value =
detail::tl_index_of<typename Trait::types, T>::value;
};
template <class Trait, class T>
constexpr sum_type_token<T, sum_type_index<Trait, T>::value>
make_sum_type_token() {
return {};
}
/// Returns a reference to the value of a sum type.
/// @pre `holds_alternative<T>(x)`
/// @relates SumType
template <class T, class U>
detail::enable_if_t<SumType<U>(), T&> get(U& x) {
using namespace detail;
using trait = sum_type_access<U>;
int_token<tl_index_where<typename trait::types,
tbind<is_same_ish, T>::template type>::value> token;
// Silence compiler error about "binding to unrelated types" such as
// 'signed char' to 'char' (which is obvious bullshit).
return reinterpret_cast<T&>(trait::get(x, token));
template <class T, class U, class Trait = sum_type_access<U>>
auto get(U& x) -> decltype(Trait::get(x, make_sum_type_token<Trait, T>())) {
return Trait::get(x, make_sum_type_token<Trait, T>());
}
/// Returns a reference to the value of a sum type.
/// @pre `holds_alternative<T>(x)`
/// @relates SumType
template <class T, class U>
detail::enable_if_t<SumType<U>(), const T&> get(const U& x) {
using namespace detail;
using trait = sum_type_access<U>;
int_token<tl_index_where<typename trait::types,
tbind<is_same_ish, T>::template type>::value> token;
// Silence compiler error about "binding to unrelated types" such as
// 'signed char' to 'char' (which is obvious bullshit).
return reinterpret_cast<const T&>(trait::get(x, token));
template <class T, class U, class Trait = sum_type_access<U>>
auto get(const U& x)
-> decltype(Trait::get(x, make_sum_type_token<Trait, T>())) {
return Trait::get(x, make_sum_type_token<Trait, T>());
}
/// Returns a pointer to the value of a sum type if it is of type `T`,
/// `nullptr` otherwise.
/// @relates SumType
template <class T, class U>
detail::enable_if_t<SumType<U>(), T*> get_if(U* x) {
using namespace detail;
using trait = sum_type_access<U>;
int_token<tl_index_where<typename trait::types,
tbind<is_same_ish, T>::template type>::value> token;
return trait::is(*x, token) ? &trait::get(*x, token) : nullptr;
template <class T, class U, class Trait = sum_type_access<U>>
auto get_if(U* x)
-> decltype(Trait::get_if(x, make_sum_type_token<Trait, T>())) {
return Trait::get_if(x, make_sum_type_token<Trait, T>());
}
/// Returns a pointer to the value of a sum type if it is of type `T`,
/// `nullptr` otherwise.
/// @relates SumType
template <class T, class U>
detail::enable_if_t<SumType<U>(), const T*> get_if(const U* x) {
using namespace detail;
using trait = sum_type_access<U>;
using token_type =
int_token<tl_index_where<typename trait::types,
tbind<is_same_ish, T>::template type>::value>;
token_type token;
static_assert(token_type::value != -1, "T is not part of the sum type");
return trait::is(*x, token) ? &trait::get(*x, token) : nullptr;
template <class T, class U, class Trait = sum_type_access<U>>
auto get_if(const U* x)
-> decltype(Trait::get_if(x, make_sum_type_token<Trait, T>())) {
return Trait::get_if(x, make_sum_type_token<Trait, T>());
}
/// Returns whether a sum type has a value of type `T`.
......@@ -101,9 +100,7 @@ template <class T, class U>
bool holds_alternative(const U& x) {
using namespace detail;
using trait = sum_type_access<U>;
int_token<tl_index_where<typename trait::types,
tbind<is_same_ish, T>::template type>::value> token;
return trait::is(x, token);
return trait::is(x, make_sum_type_token<trait, T>());
}
template <bool Valid, class F, class... Ts>
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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 <type_traits>
namespace caf {
template <class T, int Pos>
struct sum_type_token {
static constexpr auto pos = std::integral_constant<int, Pos>{};
};
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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. *
******************************************************************************/
#include "caf/config.hpp"
#define CAF_SUITE sum_type_token
#include "caf/test/dsl.hpp"
#include "caf/sum_type_token.hpp"
namespace {
struct fixture {
};
} // namespace <anonymous>
CAF_TEST_FIXTURE_SCOPE(sum_type_token_tests, fixture)
CAF_TEST(todo) {
// implement me
}
CAF_TEST_FIXTURE_SCOPE_END()
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