Unverified Commit 4d3e2683 authored by Joseph Noir's avatar Joseph Noir Committed by GitHub

Merge pull request #877

Fix output of --dump-config
parents c4b567ab 43096238
......@@ -106,6 +106,10 @@ public:
/// @private
settings content;
/// Extracts all parameters from the config, including entries with default
/// values.
virtual settings dump_content() const;
/// Sets a config by using its INI name `config_name` to `config_value`.
template <class T>
actor_system_config& set(string_view name, T&& value) {
......
......@@ -127,22 +127,22 @@ public:
const char* type_name() const noexcept;
/// Returns the underlying variant.
inline variant_type& get_data() {
variant_type& get_data() {
return data_;
}
/// Returns the underlying variant.
inline const variant_type& get_data() const {
const variant_type& get_data() const {
return data_;
}
/// Returns a pointer to the underlying variant.
inline variant_type* get_data_ptr() {
variant_type* get_data_ptr() {
return &data_;
}
/// Returns a pointer to the underlying variant.
inline const variant_type* get_data_ptr() const {
const variant_type* get_data_ptr() const {
return &data_;
}
......@@ -153,18 +153,22 @@ private:
// -- auto conversion of related types ---------------------------------------
inline void set(bool x) {
void set(bool x) {
data_ = x;
}
inline void set(float x) {
void set(float x) {
data_ = static_cast<double>(x);
}
inline void set(const char* x) {
void set(const char* x) {
data_ = std::string{x};
}
void set(string_view x) {
data_ = std::string{x.begin(), x.end()};
}
template <class T>
detail::enable_if_t<detail::is_one_of<T, real, atom, timespan, uri, string,
list, dictionary>::value>
......@@ -172,6 +176,38 @@ private:
data_ = std::move(x);
}
template <class T>
detail::enable_if_t<detail::is_list_like<detail::decay_t<T>>::value
&& !std::is_same<detail::decay_t<T>, list>::value>
set(T&& xs) {
// Move values from the old list into the new list if `xs` is an rvalue.
using namespace detail;
using xs_type = decltype(xs);
using value_type = typename decay_t<T>::value_type;
using fwd_type = conditional_t<std::is_rvalue_reference<xs_type>::value,
value_type&&, const value_type&>;
auto& lst = as_list();
lst.clear();
for (auto& x : xs)
lst.emplace_back(config_value{static_cast<fwd_type>(x)});
}
template <class T>
detail::enable_if_t<detail::is_map_like<detail::decay_t<T>>::value
&& !std::is_same<detail::decay_t<T>, dictionary>::value>
set(T&& xs) {
// Move values from the old list into the new list if `xs` is an rvalue.
using namespace detail;
using xs_type = decltype(xs);
using mapped_type = typename decay_t<T>::mapped_type;
using fwd_type = conditional_t<std::is_rvalue_reference<xs_type>::value,
mapped_type&&, const mapped_type&>;
auto& dict = as_dictionary();
dict.clear();
for (auto& kvp : xs)
dict.emplace(kvp.first, static_cast<fwd_type>(kvp.second));
}
template <class T>
detail::enable_if_t<std::is_integral<T>::value> set(T x) {
data_ = static_cast<int64_t>(x);
......
......@@ -33,27 +33,52 @@
#include "caf/detail/type_list.hpp"
#define CAF_HAS_MEMBER_TRAIT(name) \
template <class T> \
struct has_##name##_member { \
template <class T> \
class has_##name##_member { \
private: \
template <class U> \
static auto sfinae(U* x) -> decltype(x->name(), std::true_type()); \
\
template <class U> \
static auto sfinae(...) -> std::false_type; \
\
using type = decltype(sfinae<T>(nullptr)); \
static constexpr bool value = type::value; \
}
using sfinae_type = decltype(sfinae<T>(nullptr)); \
\
public: \
static constexpr bool value = sfinae_type::value; \
}
#define CAF_HAS_ALIAS_TRAIT(name) \
template <class T> \
class has_##name##_alias { \
private: \
template <class C> \
static std::true_type sfinae(C* ptr, typename C::name* arg = nullptr); \
\
static std::false_type sfinae(void* ptr); \
\
using sfinae_type = decltype(sfinae(static_cast<T*>(nullptr))); \
\
public: \
static constexpr bool value = sfinae_type::value; \
}
namespace caf {
namespace detail {
// -- backport of C++14 additions ----------------------------------------------
template <class T>
using decay_t = typename std::decay<T>::type;
template <bool B, class T, class F>
using conditional_t = typename std::conditional<B, T, F>::type;
template <bool V, class T = void>
using enable_if_t = typename std::enable_if<V, T>::type;
// -- custom traits ------------------------------------------------------------
template <class Trait, class T = void>
using enable_if_tt = typename std::enable_if<Trait::value, T>::type;
......@@ -708,6 +733,35 @@ struct is_same_ish
template <class>
struct always_false : std::false_type {};
// -- traits to check for STL-style type aliases -------------------------------
CAF_HAS_ALIAS_TRAIT(value_type);
CAF_HAS_ALIAS_TRAIT(key_type);
CAF_HAS_ALIAS_TRAIT(mapped_type);
// -- constexpr functions for use in enable_if & friends -----------------------
/// Checks whether T behaves like a `std::map` or a `std::unordered_map`.
template <class T>
struct is_map_like {
static constexpr bool value = is_iterable<T>::value
&& has_key_type_alias<T>::value
&& has_mapped_type_alias<T>::value;
};
/// Checks whether T behaves like a `std::vector` or a `std::list`.
template <class T>
struct is_list_like {
static constexpr bool value = is_iterable<T>::value
&& has_value_type_alias<T>::value
&& !has_key_type_alias<T>::value
&& !has_mapped_type_alias<T>::value;
};
} // namespace detail
} // namespace caf
#undef CAF_HAS_MEMBER_TRAIT
#undef CAF_HAS_ALIAS_TRAIT
......@@ -30,29 +30,18 @@ namespace caf {
/// @relates config_value
using settings = dictionary<config_value>;
/// Tries to retrieve the value associated to `name` from `xs`.
/// @relates config_value
const config_value* get_if(const settings* xs, string_view name);
/// Tries to retrieve the value associated to `name` from `xs`.
/// @relates config_value
template <class T>
optional<T> get_if(const settings* xs, string_view name) {
// Access the key directly unless the user specified a dot-separated path.
auto pos = name.find('.');
if (pos == std::string::npos) {
auto i = xs->find(name);
if (i == xs->end())
return none;
// We can't simply return the result here, because it might be a pointer.
auto result = get_if<T>(&i->second);
if (result)
return *result;
return none;
}
// We're dealing with a `<category>.<key>`-formatted string, extract the
// sub-settings by category and recurse.
auto i = xs->find(name.substr(0, pos));
if (i == xs->end() || !holds_alternative<config_value::dictionary>(i->second))
if (auto value = get_if(xs, name))
if (auto ptr = get_if<T>(value))
return *ptr;
return none;
return get_if<T>(&get<config_value::dictionary>(i->second),
name.substr(pos + 1));
}
template <class T>
......@@ -92,6 +81,19 @@ config_value& put(settings& dict, string_view key, T&& value) {
return put_impl(dict, key, tmp);
}
/// Converts `value` to a `config_value` and assigns it to `key` if `value` is
/// currently missing in `xs`.
/// @param xs Dictionary of key-value pairs.
/// @param key Human-readable nested keys in the form `category.key`.
/// @param value New value for given `key`.
template <class T>
void put_missing(settings& xs, string_view key, T&& value) {
if (get_if(&xs, key) != nullptr)
return;
config_value tmp{std::forward<T>(value)};
put_impl(xs, key, tmp);
}
/// Inserts a new list named `name` into the dictionary `xs` and returns
/// a reference to it. Overrides existing entries with the same name.
config_value::list& put_list(settings& xs, std::string name);
......
......@@ -129,12 +129,6 @@ actor_system_config::actor_system_config()
"schedule utility actors instead of dedicating threads")
.add<bool>("manual-multiplexing",
"disables background activity of the multiplexer")
.add<size_t>("cached-udp-buffers",
"maximum for cached UDP send buffers (default: 10)")
.add<size_t>("max-pending-messages",
"maximum for reordering of UDP receive buffers (default: 10)")
.add<bool>("disable-tcp", "disables communication via TCP")
.add<bool>("enable-udp", "enable communication via UDP")
.add<size_t>("workers", "number of deserialization workers");
opt_group(custom_options_, "opencl")
.add<std::vector<size_t>>("device-ids", "whitelist for OpenCL devices");
......@@ -154,6 +148,73 @@ actor_system_config::actor_system_config()
error_renderers.emplace(atom("exit"), render_exit_reason);
}
settings actor_system_config::dump_content() const {
settings result = content;
// -- streaming parameters
auto& stream_group = result["stream"].as_dictionary();
put_missing(stream_group, "desired-batch-complexity",
defaults::stream::desired_batch_complexity);
put_missing(stream_group, "max-batch-delay",
defaults::stream::max_batch_delay);
put_missing(stream_group, "credit-round-interval",
defaults::stream::credit_round_interval);
// -- scheduler parameters
auto& scheduler_group = result["scheduler"].as_dictionary();
put_missing(scheduler_group, "policy", defaults::scheduler::policy);
put_missing(scheduler_group, "max-threads", defaults::scheduler::max_threads);
put_missing(scheduler_group, "max-throughput",
defaults::scheduler::max_throughput);
put_missing(scheduler_group, "enable-profiling", false);
put_missing(scheduler_group, "profiling-resolution",
defaults::scheduler::profiling_resolution);
put_missing(scheduler_group, "profiling-output-file", std::string{});
// -- work-stealing parameters
auto& work_stealing_group = result["work-stealing"].as_dictionary();
put_missing(work_stealing_group, "aggressive-poll-attempts",
defaults::work_stealing::aggressive_poll_attempts);
put_missing(work_stealing_group, "aggressive-steal-interval",
defaults::work_stealing::aggressive_steal_interval);
put_missing(work_stealing_group, "moderate-poll-attempts",
defaults::work_stealing::moderate_poll_attempts);
put_missing(work_stealing_group, "moderate-steal-interval",
defaults::work_stealing::moderate_steal_interval);
put_missing(work_stealing_group, "moderate-sleep-duration",
defaults::work_stealing::moderate_sleep_duration);
put_missing(work_stealing_group, "relaxed-steal-interval",
defaults::work_stealing::relaxed_steal_interval);
put_missing(work_stealing_group, "relaxed-sleep-duration",
defaults::work_stealing::relaxed_sleep_duration);
// -- logger parameters
auto& logger_group = result["logger"].as_dictionary();
put_missing(logger_group, "file-name", defaults::logger::file_name);
put_missing(logger_group, "file-format", defaults::logger::file_format);
put_missing(logger_group, "file-verbosity", defaults::logger::file_verbosity);
put_missing(logger_group, "console", defaults::logger::console);
put_missing(logger_group, "console-format", defaults::logger::console_format);
put_missing(logger_group, "console-verbosity",
defaults::logger::console_verbosity);
put_missing(logger_group, "component-blacklist", std::vector<atom_value>{});
put_missing(logger_group, "inline-output", false);
// -- middleman parameters
auto& middleman_group = result["middleman"].as_dictionary();
put_missing(middleman_group, "app-identifiers",
defaults::middleman::app_identifiers);
put_missing(middleman_group, "enable-automatic-connections", false);
put_missing(middleman_group, "max-consecutive-reads",
defaults::middleman::max_consecutive_reads);
put_missing(middleman_group, "heartbeat-interval",
defaults::middleman::heartbeat_interval);
put_missing(middleman_group, "workers", defaults::middleman::workers);
// -- opencl parameters
auto& openssl_group = result["openssl"].as_dictionary();
put_missing(openssl_group, "certificate", std::string{});
put_missing(openssl_group, "key", std::string{});
put_missing(openssl_group, "passphrase", std::string{});
put_missing(openssl_group, "capath", std::string{});
put_missing(openssl_group, "cafile", std::string{});
return result;
}
std::string
actor_system_config::make_help_text(const std::vector<message::cli_arg>& xs) {
auto is_no_caf_option = [](const message::cli_arg& arg) {
......@@ -238,6 +299,45 @@ bool operator!=(ini_iter iter, ini_sentinel) {
return !iter.ini->fail();
}
struct indentation {
size_t size;
};
indentation operator+(indentation x, size_t y) noexcept {
return {x.size + y};
}
std::ostream& operator<<(std::ostream& out, indentation indent) {
for (size_t i = 0; i < indent.size; ++i)
out.put(' ');
return out;
}
void print(const config_value::dictionary& xs, indentation indent) {
using std::cout;
for (const auto& kvp : xs) {
if (kvp.first == "dump-config")
continue;
if (auto submap = get_if<config_value::dictionary>(&kvp.second)) {
cout << indent << kvp.first << " {\n";
print(*submap, indent + 2);
cout << indent << "}\n";
} else if (auto lst = get_if<config_value::list>(&kvp.second)) {
if (lst->empty()) {
cout << indent << kvp.first << " = []\n";
} else {
cout << indent << kvp.first << " = [\n";
auto list_indent = indent + 2;
for (auto& x : *lst)
cout << list_indent << to_string(x) << ",\n";
cout << indent << "]\n";
}
} else {
cout << indent << kvp.first << " = " << to_string(kvp.second) << '\n';
}
}
};
} // namespace <anonymous>
error actor_system_config::parse(string_list args, std::istream& ini) {
......@@ -269,16 +369,9 @@ error actor_system_config::parse(string_list args, std::istream& ini) {
bool long_help = get_or(content, "long-help", false);
std::cout << custom_options_.help_text(!long_help) << std::endl;
}
// Generate INI dump if needed.
// Generate config dump if needed.
if (!cli_helptext_printed && get_or(content, "dump-config", false)) {
for (auto& category : content) {
if (auto dict = get_if<config_value::dictionary>(&category.second)) {
std::cout << '[' << category.first << "]\n";
for (auto& kvp : *dict)
if (kvp.first != "dump-config")
std::cout << kvp.first << '=' << to_string(kvp.second) << '\n';
}
}
print(dump_content(), indentation{0});
std::cout << std::flush;
cli_helptext_printed = true;
}
......
......@@ -22,6 +22,25 @@
namespace caf {
const config_value* get_if(const settings* xs, string_view name) {
// Access the key directly unless the user specified a dot-separated path.
auto pos = name.find('.');
if (pos == std::string::npos) {
auto i = xs->find(name);
if (i == xs->end())
return nullptr;
// We can't simply return the result here, because it might be a pointer.
return &i->second;
}
// We're dealing with a `<category>.<key>`-formatted string, extract the
// sub-settings by category and recurse.
auto i = xs->find(name.substr(0, pos));
if (i == xs->end() || !holds_alternative<config_value::dictionary>(i->second))
return nullptr;
return get_if(&get<config_value::dictionary>(i->second),
name.substr(pos + 1));
}
std::string get_or(const settings& xs, string_view name,
string_view default_value) {
auto result = get_if<std::string>(&xs, name);
......
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