Commit 438e0bf4 authored by Dominik Charousset's avatar Dominik Charousset

Add getter for option values

parent 2b2b35a9
......@@ -32,10 +32,18 @@ public:
/// Custom vtable-like struct for delegating to type-specific functions and
/// storing type-specific information shared by several config options.
struct meta_state {
/// Checks whether a value matches the option's type.
error (*check)(const config_value&);
/// Stores a value in the given location.
void (*store)(void*, const config_value&);
/// Tries to extrac a value from the given location. Exists for backward
/// compatibility only and will get removed with CAF 0.17.
config_value (*get)(const void*);
/// Human-readable name of the option's type.
std::string type_name;
bool is_flag;
};
// -- constructors, destructors, and assignment operators --------------------
......@@ -83,6 +91,10 @@ public:
/// Returns whether this config option stores a boolean flag.
bool is_flag() const noexcept;
/// @private
// TODO: remove with CAF 0.17
optional<config_value> get() const;
private:
std::string category_;
std::string long_name_;
......
......@@ -18,6 +18,8 @@
#pragma once
#include <memory>
#include "caf/config_option.hpp"
#include "caf/config_value.hpp"
#include "caf/detail/type_name.hpp"
......@@ -25,40 +27,42 @@
namespace caf {
namespace detail {
template <class T>
struct option_meta_state {
static config_option::meta_state instance;
};
template <class T>
config_option::meta_state option_meta_state<T>::instance{
[](const config_value& x) -> error {
if (holds_alternative<T>(x))
return none;
return make_error(pec::type_mismatch);
},
[](void* ptr, const config_value& x) {
*static_cast<T*>(ptr) = get<T>(x);
},
nullptr,
detail::type_name<T>()
};
} // namespace detail
/// Creates a config option that synchronizes with `storage`.
template <class T>
config_option make_config_option(const char* category, const char* name,
const char* description) {
static config_option::meta_state meta{
[](const config_value& x) -> error {
if (holds_alternative<T>(x))
return none;
return make_error(pec::type_mismatch);
},
nullptr,
detail::type_name<T>(),
false
};
return {category, name, description, &meta};
return {category, name, description, &detail::option_meta_state<T>::instance};
}
/// Creates a config option that synchronizes with `storage`.
template <class T>
config_option make_config_option(T& storage, const char* category,
const char* name, const char* description) {
static config_option::meta_state meta{
[](const config_value& x) -> error {
if (holds_alternative<T>(x))
return none;
return make_error(pec::type_mismatch);
},
[](void* ptr, const config_value& x) {
*static_cast<T*>(ptr) = get<T>(x);
},
detail::type_name<T>(),
false
};
return {category, name, description, &meta, &storage};
return {category, name, description, &detail::option_meta_state<T>::instance,
std::addressof(storage)};
}
// -- backward compatbility, do not use for new code ! -------------------------
......@@ -68,15 +72,29 @@ config_option make_negated_config_option(bool& storage, const char* category,
const char* name,
const char* description);
// -- specializations for common types.
// Reads timespans, but stores an integer representing microsecond resolution.
config_option make_us_resolution_config_option(size_t& storage,
const char* category,
const char* name,
const char* description);
// -- specializations for common types -----------------------------------------
#define CAF_SPECIALIZE_MAKE_CONFIG_OPTION(type) \
template <> \
config_option make_config_option<std::string>( \
std::string & storage, const char* category, const char* name, \
const char* description); \
template <> \
config_option make_config_option<std::string>( \
const char* category, const char* name, const char* description)
CAF_SPECIALIZE_MAKE_CONFIG_OPTION(atom_value);
CAF_SPECIALIZE_MAKE_CONFIG_OPTION(bool);
template <>
config_option make_config_option<bool>(const char* category, const char* name,
const char* description);
CAF_SPECIALIZE_MAKE_CONFIG_OPTION(size_t);
template <>
config_option make_config_option<bool>(bool& storage, const char* category,
const char* name,
const char* description);
CAF_SPECIALIZE_MAKE_CONFIG_OPTION(std::string);
} // namespace caf
......@@ -21,7 +21,9 @@
#include <iostream>
#include "caf/config.hpp"
#include "caf/config_value.hpp"
#include "caf/error.hpp"
#include "caf/optional.hpp"
using std::move;
using std::string;
......@@ -80,7 +82,13 @@ const std::string& config_option::type_name() const noexcept {
}
bool config_option::is_flag() const noexcept {
return meta_->is_flag;
return type_name() == "boolean";
}
optional<config_value> config_option::get() const {
if (value_ != nullptr && meta_->get != nullptr)
return meta_->get(value_);
return none;
}
} // namespace caf
......@@ -18,12 +18,54 @@
#include "caf/make_config_option.hpp"
#include "caf/config_value.hpp"
#include "caf/optional.hpp"
using std::string;
namespace caf {
namespace {
using meta_state = config_option::meta_state;
template <class T>
error check_impl(const config_value& x) {
if (holds_alternative<T>(x))
return none;
return make_error(pec::type_mismatch);
}
template <class T>
void store_impl(void* ptr, const config_value& x) {
CAF_ASSERT(ptr != nullptr);
*static_cast<T*>(ptr) = get<T>(x);
}
template <class T>
config_value get_impl(const void* ptr) {
CAF_ASSERT(ptr != nullptr);
return config_value{*static_cast<const T*>(ptr)};
}
#define DEFAULT_META(type) \
meta_state type##_meta{check_impl<type>, store_impl<type>, get_impl<type>, \
detail::type_name<type>()}
#define DEFAULT_MAKE_IMPL(type) \
template <> \
config_option make_config_option<type>(type & storage, const char* category, \
const char* name, \
const char* description) { \
return {category, name, description, &type##_meta, &storage}; \
} \
template <> \
config_option make_config_option<type>(const char* category, \
const char* name, \
const char* description) { \
return {category, name, description, &type##_meta, nullptr}; \
}
error bool_check(const config_value& x) {
if (holds_alternative<bool>(x))
return none;
......@@ -38,10 +80,42 @@ void bool_store_neg(void* ptr, const config_value& x) {
*static_cast<bool*>(ptr) = !get<bool>(x);
}
meta_state bool_meta{bool_check, bool_store, detail::type_name<bool>(), true};
config_value bool_get(const void* ptr) {
return config_value{static_cast<const bool*>(ptr)};
}
config_value bool_get_neg(const void* ptr) {
return config_value{!static_cast<const bool*>(ptr)};
}
meta_state bool_meta{bool_check, bool_store, bool_get,
detail::type_name<bool>()};
meta_state bool_neg_meta{bool_check, bool_store_neg, bool_get_neg,
detail::type_name<bool>()};
meta_state entangled_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) = get<timespan>(x).count() / 1000;
},
[](const void* ptr) -> config_value {
auto ival = static_cast<int64_t>(*static_cast<const size_t*>(ptr));
timespan val{ival / 1000};
return config_value{val};
},
detail::type_name<timespan>()
};
meta_state bool_neg_meta{bool_check, bool_store_neg, detail::type_name<bool>(),
true};
DEFAULT_META(atom_value);
DEFAULT_META(size_t);
DEFAULT_META(string);
} // namespace anonymous
......@@ -51,17 +125,19 @@ config_option make_negated_config_option(bool& storage, const char* category,
return {category, name, description, &bool_neg_meta, &storage};
}
template <>
config_option make_config_option<bool>(const char* category, const char* name,
const char* description) {
return {category, name, description, &bool_meta};
config_option make_us_resolution_config_option(size_t& storage,
const char* category,
const char* name,
const char* description) {
return {category, name, description, &entangled_meta, &storage};
}
template <>
config_option make_config_option<bool>(bool& storage, const char* category,
const char* name,
const char* description) {
return {category, name, description, &bool_meta, &storage};
}
DEFAULT_MAKE_IMPL(atom_value)
DEFAULT_MAKE_IMPL(bool)
DEFAULT_MAKE_IMPL(size_t)
DEFAULT_MAKE_IMPL(string)
} // namespace caf
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