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

Implement SumType trait for config_value

parent 90026f8e
...@@ -30,6 +30,9 @@ ...@@ -30,6 +30,9 @@
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/optional.hpp" #include "caf/optional.hpp"
#include "caf/string_algorithms.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/timestamp.hpp"
#include "caf/variant.hpp" #include "caf/variant.hpp"
...@@ -122,6 +125,16 @@ public: ...@@ -122,6 +125,16 @@ public:
return data_; 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: private:
// -- properties ------------------------------------------------------------- // -- properties -------------------------------------------------------------
...@@ -158,54 +171,122 @@ private: ...@@ -158,54 +171,122 @@ private:
variant_type data_; variant_type data_;
}; };
// -- related type aliases -----------------------------------------------------
/// Organizes config values into categories. /// Organizes config values into categories.
/// @relates config_value /// @relates config_value
using config_value_map = std::map<std::string, config_value::dictionary>; using config_value_map = std::map<std::string, config_value::dictionary>;
// -- SumType-like access ------------------------------------------------------
/// @relates config_value /// @relates config_value
template <class T> template <class T>
struct config_value_access { struct config_value_access;
static constexpr bool specialized = false;
/// 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> 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 constexpr bool specialized = true;
static bool is(const config_value& x) { template <class U, int Pos>
return holds_alternative<T>(x.get_data()); 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) { template <class U>
return caf::get_if<T>(&(x->get_data())); 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) { template <class U, int Pos>
return caf::get_if<T>(&(x->get_data())); 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) { template <class U>
return caf::get<T>(x.get_data()); 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 <class U>
template <> \ static U get(const config_value& x, sum_type_token<U, -1>) {
struct config_value_access<config_value::subtype> \ return select_config_value_access_t<U>::get(x);
: default_config_value_access<config_value::subtype> {} }
CAF_CONFIG_VALUE_DEFAULT_ACCESS(integer); template <class U, int Pos>
CAF_CONFIG_VALUE_DEFAULT_ACCESS(boolean); static U* get_if(config_value* x, sum_type_token<U, Pos> token) {
CAF_CONFIG_VALUE_DEFAULT_ACCESS(real); return is(*x, token) ? &get(*x, token) : nullptr;
CAF_CONFIG_VALUE_DEFAULT_ACCESS(atom); }
CAF_CONFIG_VALUE_DEFAULT_ACCESS(timespan);
CAF_CONFIG_VALUE_DEFAULT_ACCESS(string); template <class U>
CAF_CONFIG_VALUE_DEFAULT_ACCESS(list); static optional<U> get_if(config_value* x, sum_type_token<U, -1>) {
CAF_CONFIG_VALUE_DEFAULT_ACCESS(dictionary); 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 <> template <>
struct config_value_access<float> { struct config_value_access<float> {
...@@ -285,7 +366,7 @@ struct config_value_access<std::map<std::string, V>> { ...@@ -285,7 +366,7 @@ struct config_value_access<std::map<std::string, V>> {
auto lst = caf::get_if<config_value::dictionary>(&x); auto lst = caf::get_if<config_value::dictionary>(&x);
if (lst != nullptr) { if (lst != nullptr) {
return std::all_of(lst->begin(), lst->end(), [](const kvp& x) { 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; return false;
...@@ -315,6 +396,8 @@ struct config_value_access<std::map<std::string, V>> { ...@@ -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`. /// Tries to retrieve the value associated to `name` from `xs`.
/// @relates config_value /// @relates config_value
template <class T> template <class T>
...@@ -446,100 +529,6 @@ T get_or(const actor_system_config& cfg, const std::string& name, ...@@ -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, std::string get_or(const actor_system_config& cfg, const std::string& name,
const char* default_value); 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 /// @relates config_value
bool operator<(const config_value& x, const config_value& y); bool operator<(const config_value& x, const config_value& y);
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <utility> #include <utility>
#include "caf/detail/type_list.hpp" #include "caf/detail/type_list.hpp"
#include "caf/sum_type_token.hpp"
namespace caf { namespace caf {
...@@ -36,21 +37,29 @@ struct default_sum_type_access { ...@@ -36,21 +37,29 @@ struct default_sum_type_access {
static constexpr bool specialized = true; static constexpr bool specialized = true;
template <int Pos> template <class U, int Pos>
static bool is(const T& x, std::integral_constant<int, Pos> token) { static bool is(const T& x, sum_type_token<U, Pos> token) {
return x.get_data().is(token); return x.get_data().is(token.pos);
} }
template <int Pos> template <class U, int Pos>
static typename detail::tl_at<types, Pos>::type& static U& get(T& x, sum_type_token<U, Pos> token) {
get(T& x, std::integral_constant<int, Pos> token) { return x.get_data().get(token.pos);
return x.get_data().get(token);
} }
template <int Pos> template <class U, int Pos>
static const typename detail::tl_at<types, Pos>::type& static const U& get(const T& x, sum_type_token<U, Pos> token) {
get(const T& x, std::integral_constant<int, Pos> token) { return x.get_data().get(token.pos);
return x.get_data().get(token); }
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> template <class Result, class Visitor, class... Ts>
......
...@@ -159,31 +159,6 @@ enum class atom_value : uint64_t; ...@@ -159,31 +159,6 @@ enum class atom_value : uint64_t;
using actor_id = uint64_t; using actor_id = uint64_t;
using stream_slot = uint16_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 ---------------------------------------------------------------- // -- functions ----------------------------------------------------------------
/// @relates actor_system_config /// @relates actor_system_config
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <memory> #include <memory>
#include "caf/config_option.hpp" #include "caf/config_option.hpp"
#include "caf/config_value.hpp"
#include "caf/detail/type_name.hpp" #include "caf/detail/type_name.hpp"
#include "caf/error.hpp" #include "caf/error.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "caf/detail/type_list.hpp" #include "caf/detail/type_list.hpp"
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
#include "caf/sum_type_access.hpp" #include "caf/sum_type_access.hpp"
#include "caf/sum_type_token.hpp"
namespace caf { namespace caf {
...@@ -40,59 +41,57 @@ constexpr bool SumTypes() { ...@@ -40,59 +41,57 @@ constexpr bool SumTypes() {
return tl_forall<types, has_sum_type_access>::value; 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. /// Returns a reference to the value of a sum type.
/// @pre `holds_alternative<T>(x)` /// @pre `holds_alternative<T>(x)`
/// @relates SumType /// @relates SumType
template <class T, class U> template <class T, class U, class Trait = sum_type_access<U>>
detail::enable_if_t<SumType<U>(), T&> get(U& x) { auto get(U& x) -> decltype(Trait::get(x, make_sum_type_token<Trait, T>())) {
using namespace detail; return Trait::get(x, make_sum_type_token<Trait, T>());
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));
} }
/// Returns a reference to the value of a sum type. /// Returns a reference to the value of a sum type.
/// @pre `holds_alternative<T>(x)` /// @pre `holds_alternative<T>(x)`
/// @relates SumType /// @relates SumType
template <class T, class U> template <class T, class U, class Trait = sum_type_access<U>>
detail::enable_if_t<SumType<U>(), const T&> get(const U& x) { auto get(const U& x)
using namespace detail; -> decltype(Trait::get(x, make_sum_type_token<Trait, T>())) {
using trait = sum_type_access<U>; return Trait::get(x, make_sum_type_token<Trait, T>());
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));
} }
/// Returns a pointer to the value of a sum type if it is of type `T`, /// Returns a pointer to the value of a sum type if it is of type `T`,
/// `nullptr` otherwise. /// `nullptr` otherwise.
/// @relates SumType /// @relates SumType
template <class T, class U> template <class T, class U, class Trait = sum_type_access<U>>
detail::enable_if_t<SumType<U>(), T*> get_if(U* x) { auto get_if(U* x)
using namespace detail; -> decltype(Trait::get_if(x, make_sum_type_token<Trait, T>())) {
using trait = sum_type_access<U>; return Trait::get_if(x, make_sum_type_token<Trait, T>());
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;
} }
/// Returns a pointer to the value of a sum type if it is of type `T`, /// Returns a pointer to the value of a sum type if it is of type `T`,
/// `nullptr` otherwise. /// `nullptr` otherwise.
/// @relates SumType /// @relates SumType
template <class T, class U> template <class T, class U, class Trait = sum_type_access<U>>
detail::enable_if_t<SumType<U>(), const T*> get_if(const U* x) { auto get_if(const U* x)
using namespace detail; -> decltype(Trait::get_if(x, make_sum_type_token<Trait, T>())) {
using trait = sum_type_access<U>; return Trait::get_if(x, make_sum_type_token<Trait, T>());
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;
} }
/// Returns whether a sum type has a value of type `T`. /// Returns whether a sum type has a value of type `T`.
...@@ -101,9 +100,7 @@ template <class T, class U> ...@@ -101,9 +100,7 @@ template <class T, class U>
bool holds_alternative(const U& x) { bool holds_alternative(const U& x) {
using namespace detail; using namespace detail;
using trait = sum_type_access<U>; using trait = sum_type_access<U>;
int_token<tl_index_where<typename trait::types, return trait::is(x, make_sum_type_token<trait, T>());
tbind<is_same_ish, T>::template type>::value> token;
return trait::is(x, token);
} }
template <bool Valid, class F, class... Ts> 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