Commit 4cd321b1 authored by Dominik Charousset's avatar Dominik Charousset

Move to settings alias, change parse signature

Consequently use the new settings type alias and drop config_value_map
entirely. All parse functions in actor_system_config now take a settings
argument and return an error object.
parent 0541cbae
......@@ -99,6 +99,7 @@ set(LIBCAF_CORE_SRCS
src/sequencer.cpp
src/serializer.cpp
src/set_thread_name.cpp
src/settings.cpp
src/shared_spinlock.cpp
src/simple_actor_clock.cpp
src/skip.cpp
......
......@@ -35,6 +35,7 @@
#include "caf/fwd.hpp"
#include "caf/is_typed_actor.hpp"
#include "caf/named_actor_config.hpp"
#include "caf/settings.hpp"
#include "caf/stream.hpp"
#include "caf/thread_hook.hpp"
#include "caf/type_erased_value.hpp"
......@@ -103,7 +104,7 @@ public:
// -- properties -------------------------------------------------------------
/// @private
dictionary<config_value::dictionary> content;
settings content;
/// Sets a config by using its INI name `config_name` to `config_value`.
template <class T>
......@@ -113,25 +114,23 @@ public:
// -- modifiers --------------------------------------------------------------
/// Parses `args` as tuple of strings containing CLI options
/// and `ini_stream` as INI formatted input stream.
actor_system_config& parse(string_list args, std::istream& ini);
/// Parses `args` as tuple of strings containing CLI options and `ini_stream`
/// as INI formatted input stream.
error parse(string_list args, std::istream& ini);
/// Parses `args` as tuple of strings containing CLI options and tries to
/// open `ini_file_cstr` as INI formatted config file. The parsers tries to
/// open `caf-application.ini` if `ini_file_cstr` is `nullptr`.
actor_system_config& parse(string_list args,
const char* ini_file_cstr = nullptr);
error parse(string_list args, const char* ini_file_cstr = nullptr);
/// Parses the CLI options `{argc, argv}` and
/// `ini_stream` as INI formatted input stream.
actor_system_config& parse(int argc, char** argv, std::istream& ini);
/// Parses the CLI options `{argc, argv}` and `ini_stream` as INI formatted
/// input stream.
error parse(int argc, char** argv, std::istream& ini);
/// Parses the CLI options `{argc, argv}` and tries to open `ini_file_cstr`
/// as INI formatted config file. The parsers tries to open
/// `caf-application.ini` if `ini_file_cstr` is `nullptr`.
actor_system_config& parse(int argc, char** argv,
const char* ini_file_cstr = nullptr);
error parse(int argc, char** argv, const char* ini_file_cstr = nullptr);
/// Allows other nodes to spawn actors created by `fun`
/// dynamically by using `name` as identifier.
......@@ -337,8 +336,43 @@ private:
static std::string render_exit_reason(uint8_t, atom_value, const message&);
static std::string render_pec(uint8_t, atom_value, const message&);
void extract_config_file_path(string_list& args);
};
} // namespace caf
/// @private
const settings& content(const actor_system_config& cfg);
/// Tries to retrieve the value associated to `name` from `cfg`.
/// @relates config_value
template <class T>
optional<T> get_if(const actor_system_config* cfg, string_view name) {
return get_if<T>(&content(*cfg), name);
}
/// Retrieves the value associated to `name` from `cfg`.
/// @relates config_value
template <class T>
T get(const actor_system_config& cfg, string_view name) {
return get<T>(content(cfg), name);
}
/// Retrieves the value associated to `name` from `cfg` or returns
/// `default_value`.
/// @relates config_value
template <class T, class E = detail::enable_if_t<!std::is_pointer<T>::value>>
T get_or(const actor_system_config& cfg, string_view name,
const T& default_value) {
return get_or(content(cfg), name, default_value);
}
/// Retrieves the value associated to `name` from `cfg` or returns
/// `default_value`.
/// @relates config_value
inline std::string get_or(const actor_system_config& cfg, string_view name,
string_view default_value) {
return get_or(content(cfg), name, default_value);
}
} // namespace caf
......@@ -33,7 +33,7 @@
namespace caf {
/// A set of `config_option` objects that parses CLI arguments into a
/// `config_value::dictionary`.
/// `settings` object.
class config_option_set {
public:
// -- member types -----------------------------------------------------------
......@@ -56,12 +56,6 @@ public:
/// An iterator over ::config_option unique pointers.
using const_iterator = option_vector::const_iterator;
/// Maps string keys to arbitrary (config) values.
using dictionary = caf::dictionary<config_value>;
/// Categorized settings.
using config_map = caf::dictionary<dictionary>;
// -- properties -------------------------------------------------------------
/// Returns the first `config_option` that matches the CLI name.
......@@ -174,11 +168,11 @@ public:
// -- parsing ----------------------------------------------------------------
/// Parses a given range as CLI arguments into `config`.
parse_result parse(config_map& config, argument_iterator begin,
parse_result parse(settings& config, argument_iterator begin,
argument_iterator end) const;
/// Parses a given range as CLI arguments into `config`.
parse_result parse(config_map& config,
parse_result parse(settings& config,
const std::vector<std::string>& args) const;
private:
......
......@@ -22,6 +22,7 @@
#include <cstdint>
#include <map>
#include <string>
#include <type_traits>
#include <vector>
#include "caf/atom.hpp"
......@@ -32,6 +33,7 @@
#include "caf/optional.hpp"
#include "caf/raise_error.hpp"
#include "caf/string_algorithms.hpp"
#include "caf/string_view.hpp"
#include "caf/sum_type.hpp"
#include "caf/sum_type_access.hpp"
#include "caf/sum_type_token.hpp"
......@@ -111,6 +113,12 @@ public:
/// already is a list.
void convert_to_list();
/// Returns the value as a list, converting it to one if needed.
list& as_list();
/// Returns the value as a dictionary, converting it to one if needed.
dictionary& as_dictionary();
/// Appends `x` to a list. Converts this config value to a list first by
/// calling `convert_to_list` if needed.
void append(config_value x);
......@@ -174,12 +182,6 @@ private:
variant_type data_;
};
// -- related type aliases -----------------------------------------------------
/// Organizes config values into categories.
/// @relates config_value
using config_value_map = dictionary<config_value::dictionary>;
// -- SumType-like access ------------------------------------------------------
/// @relates config_value
......@@ -401,168 +403,6 @@ struct config_value_access<dictionary<V>> {
// -- SumType-like access of dictionary values ---------------------------------
/// Tries to retrieve the value associated to `name` from `xs`.
/// @relates config_value
template <class T>
optional<T> get_if(const config_value::dictionary* xs, string_view name) {
// Split the name into a path.
std::vector<string_view> path;
split(path, name, ".");
// Sanity check.
if (path.size() == 0)
return none;
// Resolve path, i.e., find the requested submap.
auto current = xs;
auto leaf = path.end() - 1;
for (auto i = path.begin(); i != leaf; ++i) {
auto j = current->find(*i);
if (j == current->end())
return none;
current = caf::get_if<config_value::dictionary>(&j->second);
if (current == nullptr)
return none;
}
// Get the leaf value.
auto j = current->find(*leaf);
if (j == current->end())
return none;
auto result = caf::get_if<T>(&j->second);
if (result)
return *result;
return none;
}
/// Retrieves the value associated to `name` from `xs`.
/// @relates config_value
template <class T>
T get(const config_value::dictionary& xs, string_view name) {
auto result = get_if<T>(&xs, name);
if (result)
return std::move(*result);
CAF_RAISE_ERROR("invalid type or name found");
}
/// Retrieves the value associated to `name` from `xs` or returns
/// `default_value`.
/// @relates config_value
template <class T, class E = detail::enable_if_t<!std::is_pointer<T>::value>>
T get_or(const config_value::dictionary& xs, string_view name,
const T& default_value) {
auto result = get_if<T>(&xs, name);
if (result)
return std::move(*result);
return default_value;
}
/// Retrieves the value associated to `name` from `xs` or returns
/// `default_value`.
/// @relates config_value
std::string get_or(const config_value::dictionary& xs, string_view name,
const char* default_value);
/// Tries to retrieve the value associated to `name` from `xs`.
/// @relates config_value
template <class T>
optional<T> get_if(const config_value_map* xs, string_view name) {
// Get the category.
auto pos = name.find('.');
if (pos == std::string::npos) {
auto i = xs->find("global");
if (i == xs->end())
return none;
return get_if<T>(&i->second, name);
}
auto i = xs->find(name.substr(0, pos));
if (i == xs->end())
return none;
return get_if<T>(&i->second, name.substr(pos + 1));
}
/// Retrieves the value associated to `name` from `xs`.
/// @relates config_value
template <class T>
T get(const config_value_map& xs, string_view name) {
auto result = get_if<T>(&xs, name);
if (result)
return std::move(*result);
CAF_RAISE_ERROR("invalid type or name found");
}
/// Retrieves the value associated to `name` from `xs` or returns
/// `default_value`.
/// @relates config_value
template <class T, class E = detail::enable_if_t<!std::is_pointer<T>::value>>
T get_or(const config_value_map& xs, string_view name, const T& default_value) {
auto result = get_if<T>(&xs, name);
if (result)
return std::move(*result);
return default_value;
}
/// Retrieves the value associated to `name` from `xs` or returns
/// `default_value`.
/// @relates config_value
std::string get_or(const config_value_map& xs, string_view name,
const char* default_value);
/// Tries to retrieve the value associated to `name` from `cfg`.
/// @relates config_value
template <class T>
optional<T> get_if(const actor_system_config* cfg, string_view name) {
return get_if<T>(&content(*cfg), name);
}
/// Retrieves the value associated to `name` from `cfg`.
/// @relates config_value
template <class T>
T get(const actor_system_config& cfg, string_view name) {
return get<T>(content(cfg), name);
}
/// Retrieves the value associated to `name` from `cfg` or returns
/// `default_value`.
/// @relates config_value
template <class T, class E = detail::enable_if_t<!std::is_pointer<T>::value>>
T get_or(const actor_system_config& cfg, string_view name,
const T& default_value) {
return get_or(content(cfg), name, default_value);
}
std::string get_or(const actor_system_config& cfg, string_view name,
const char* default_value);
/// @private
void put_impl(config_value::dictionary& dict,
const std::vector<string_view>& path, config_value& value);
/// @private
void put_impl(config_value::dictionary& dict, string_view key,
config_value& value);
/// @private
void put_impl(dictionary<config_value::dictionary>& dict, string_view key,
config_value& value);
/// Converts `value` to a `config_value` and assigns it to `key`.
/// @param dict 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(dictionary<config_value::dictionary>& dict, string_view key,
T&& value) {
config_value tmp{std::forward<T>(value)};
put_impl(dict, 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(config_value::dictionary& xs, std::string name);
/// 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::dictionary& put_dictionary(config_value::dictionary& xs,
std::string name);
/// @relates config_value
bool operator<(const config_value& x, const config_value& y);
......@@ -595,4 +435,3 @@ typename Inspector::result_type inspect(Inspector& f, config_value& x) {
}
} // namespace caf
......@@ -22,6 +22,7 @@
#include <cstddef>
#include "caf/atom.hpp"
#include "caf/string_view.hpp"
#include "caf/timestamp.hpp"
// -- hard-coded default values for various CAF options ------------------------
......@@ -40,7 +41,7 @@ extern const timespan credit_round_interval;
namespace scheduler {
extern const atom_value policy;
extern const char* profiling_output_file;
extern string_view profiling_output_file;
extern const size_t max_threads;
extern const size_t max_throughput;
extern const timespan profiling_resolution;
......@@ -61,19 +62,19 @@ extern const timespan relaxed_sleep_duration;
namespace logger {
extern const char* component_filter;
extern string_view component_filter;
extern const atom_value console;
extern const char* console_format;
extern string_view console_format;
extern const atom_value console_verbosity;
extern const char* file_format;
extern const char* file_name;
extern string_view file_format;
extern string_view file_name;
extern const atom_value file_verbosity;
} // namespace logger
namespace middleman {
extern const char* app_identifier;
extern string_view app_identifier;
extern const atom_value network_backend;
extern const size_t max_consecutive_reads;
extern const size_t heartbeat_interval;
......
......@@ -23,6 +23,7 @@
#include "caf/config_option_set.hpp"
#include "caf/config_value.hpp"
#include "caf/dictionary.hpp"
#include "caf/settings.hpp"
namespace caf {
namespace detail {
......@@ -191,7 +192,7 @@ public:
// -- constructors, destructors, and assignment operators --------------------
ini_consumer(config_option_set& options, config_map& cfg);
ini_consumer(config_option_set& options, settings& cfg);
ini_consumer(ini_consumer&&) = default;
......@@ -207,7 +208,7 @@ private:
// -- member variables -------------------------------------------------------
config_option_set& options_;
config_map& cfg_;
settings& cfg_;
std::string current_key;
std::vector<error> warnings_;
};
......
......@@ -366,13 +366,4 @@ bool operator>=(const dictionary<T>& xs, const dictionary<T>& ys) {
return xs.container() >= ys.container();
}
// -- free functions -----------------------------------------------------------
/// Convenience function for calling `dict.insert_or_assign(key, value)`.
// @relates dictionary
template <class T, class V>
void put(dictionary<T>& dict, string_view key, V&& value) {
dict.insert_or_assign(key, std::forward<V>(value));
}
} // namespace caf
......@@ -174,13 +174,12 @@ using ip_address = ipv6_address;
using ip_subnet = ipv6_subnet;
using stream_slot = uint16_t;
using config_value_map = dictionary<dictionary<config_value>>;
using settings = dictionary<config_value>;
// -- functions ----------------------------------------------------------------
/// @relates actor_system_config
const dictionary<dictionary<config_value>>& content(const actor_system_config&);
const settings& content(const actor_system_config&);
// -- intrusive containers -----------------------------------------------------
......
......@@ -65,10 +65,18 @@ enum class pec : uint8_t {
illegal_category,
};
/// Returns an error object from given error code.
error make_error(pec code);
/// Returns an error object from given error code with additional context
/// information for where the parser stopped in the input.
error make_error(pec code, size_t line, size_t column);
/// Returns an error object from given error code with additional context
/// information for where the parser stopped in the argument.
error make_error(pec code, std::string argument);
/// @relates pec
const char* to_string(pec x);
} // namespace caf
......@@ -20,6 +20,9 @@
#include "caf/config_value.hpp"
#include "caf/dictionary.hpp"
#include "caf/optional.hpp"
#include "caf/raise_error.hpp"
#include "caf/string_view.hpp"
namespace caf {
......@@ -27,4 +30,74 @@ namespace caf {
/// @relates config_value
using settings = dictionary<config_value>;
/// 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))
return none;
return get_if<T>(&get<config_value::dictionary>(i->second),
name.substr(pos + 1));
}
template <class T>
T get(const settings& xs, string_view name) {
auto result = get_if<T>(&xs, name);
CAF_ASSERT(result != none);
return std::move(*result);
}
template <class T,
class = typename std::enable_if<!std::is_pointer<T>::value>::type>
T get_or(const settings& xs, string_view name, T default_value) {
auto result = get_if<T>(&xs, name);
if (result)
return std::move(*result);
return std::move(default_value);
}
std::string get_or(const settings& xs, string_view name,
string_view default_value);
/// @private
void put_impl(settings& dict, const std::vector<string_view>& path,
config_value& value);
/// @private
void put_impl(settings& dict, string_view key,
config_value& value);
/// Converts `value` to a `config_value` and assigns it to `key`.
/// @param dict 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(settings& dict, string_view key, T&& value) {
config_value tmp{std::forward<T>(value)};
put_impl(dict, 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);
/// 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::dictionary& put_dictionary(settings& xs, std::string name);
} // namespace caf
......@@ -32,8 +32,6 @@
#include "caf/detail/parser/read_string.hpp"
#include "caf/message_builder.hpp"
CAF_PUSH_DEPRECATED_WARNING
namespace caf {
actor_system_config::~actor_system_config() {
......@@ -57,9 +55,9 @@ actor_system_config::actor_system_config()
add_message_type_impl<std::vector<actor_addr>>("std::vector<@addr>");
add_message_type_impl<std::vector<atom_value>>("std::vector<@atom>");
add_message_type_impl<std::vector<message>>("std::vector<@message>");
add_message_type_impl<config_value_map>("config_value_map");
add_message_type_impl<config_value::list>("config_value::list");
add_message_type_impl<config_value::dictionary>("config_value::dictionary");
add_message_type_impl<settings>("settings");
add_message_type_impl<config_value::list>("std::vector<@config_value>");
add_message_type_impl<config_value::dictionary>("dictionary<@config_value>");
// (1) hard-coded defaults
stream_desired_batch_complexity = defaults::stream::desired_batch_complexity;
stream_max_batch_delay = defaults::stream::max_batch_delay;
......@@ -177,16 +175,15 @@ actor_system_config::make_help_text(const std::vector<message::cli_arg>& xs) {
return oss.str();
}
actor_system_config& actor_system_config::parse(int argc, char** argv,
const char* ini_file_cstr) {
error actor_system_config::parse(int argc, char** argv,
const char* ini_file_cstr) {
string_list args;
if (argc > 1)
args.assign(argv + 1, argv + argc);
return parse(std::move(args), ini_file_cstr);
}
actor_system_config& actor_system_config::parse(int argc, char** argv,
std::istream& ini) {
error actor_system_config::parse(int argc, char** argv, std::istream& ini) {
string_list args;
if (argc > 1)
args.assign(argv + 1, argv + argc);
......@@ -229,16 +226,7 @@ bool operator!=(ini_iter iter, ini_sentinel) {
} // namespace <anonymous>
actor_system_config& actor_system_config::parse(string_list args,
std::istream& ini) {
// Insert possibly user-defined values into the map to respect overrides to
// member variables.
// TODO: remove with CAF 0.17
for (auto& opt : custom_options_) {
auto val = opt.get();
if (val)
content[opt.category()][opt.long_name()] = std::move(*val);
}
error actor_system_config::parse(string_list args, std::istream& ini) {
// Content of the INI file overrides hard-coded defaults.
if (ini.good()) {
detail::ini_consumer consumer{custom_options_, content};
......@@ -246,14 +234,14 @@ actor_system_config& actor_system_config::parse(string_list args,
res.i = ini_iter{&ini};
detail::parser::read_ini(res, consumer);
if (res.i != res.e)
std::cerr << "*** error in config file [line " << res.line << " col "
<< res.column << "]: " << to_string(res.code) << std::endl;
return make_error(res.code, res.line, res.column);
}
// CLI options override the content of the INI file.
using std::make_move_iterator;
auto res = custom_options_.parse(content, args);
if (res.second != args.end()) {
if (res.first != pec::success) {
return make_error(res.first, *res.second);
std::cerr << "error: at argument \"" << *res.second
<< "\": " << to_string(res.first) << std::endl;
cli_helptext_printed = true;
......@@ -274,19 +262,20 @@ actor_system_config& actor_system_config::parse(string_list args,
// Generate INI dump if needed.
if (!cli_helptext_printed && get_or(content, "global.dump-config", false)) {
for (auto& category : content) {
std::cout << '[' << category.first << "]\n";
for (auto& kvp : category.second)
if (kvp.first != "dump-config")
std::cout << kvp.first << '=' << to_string(kvp.second) << '\n';
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';
}
}
std::cout << std::flush;
cli_helptext_printed = true;
}
return *this;
return none;
}
actor_system_config& actor_system_config::parse(string_list args,
const char* ini_file_cstr) {
error actor_system_config::parse(string_list args, const char* ini_file_cstr) {
// Override default config file name if set by user.
if (ini_file_cstr != nullptr)
config_file_path = ini_file_cstr;
......@@ -313,7 +302,8 @@ actor_system_config& actor_system_config::set_impl(string_view name,
auto opt = custom_options_.qualified_name_lookup(name);
if (opt != nullptr && opt->check(value) == none) {
opt->store(value);
content[opt->category()][opt->long_name()] = std::move(value);
auto& dict = content[opt->category()].as_dictionary();
dict[opt->long_name()] = std::move(value);
}
return *this;
}
......@@ -338,6 +328,13 @@ std::string actor_system_config::render_exit_reason(uint8_t x, atom_value,
meta::omittable_if_empty(), xs);
}
std::string actor_system_config::render_pec(uint8_t x, atom_value,
const message& xs) {
auto tmp = static_cast<exit_reason>(x);
return deep_to_string(meta::type_name("parser_error"), tmp,
meta::omittable_if_empty(), xs);
}
void actor_system_config::extract_config_file_path(string_list& args) {
static constexpr const char needle[] = "--caf#config-file=";
auto last = args.end();
......@@ -375,11 +372,8 @@ void actor_system_config::extract_config_file_path(string_list& args) {
args.erase(i);
}
const dictionary<dictionary<config_value>>&
content(const actor_system_config& cfg) {
const settings& content(const actor_system_config& cfg) {
return cfg.content;
}
} // namespace caf
CAF_POP_WARNINGS
......@@ -111,7 +111,7 @@ std::string config_option_set::help_text(bool global_only) const {
return std::move(builder.result);
}
auto config_option_set::parse(config_map& config, argument_iterator first,
auto config_option_set::parse(settings& config, argument_iterator first,
argument_iterator last) const
-> std::pair<pec, argument_iterator> {
// Sanity check.
......@@ -124,7 +124,10 @@ auto config_option_set::parse(config_map& config, argument_iterator first,
auto opt_name = opt.long_name();
auto opt_ctg = opt.category();
// Try inserting a new submap into the config or fill existing one.
auto& submap = config[opt_ctg];
auto& entry = config[opt_ctg];
if (!holds_alternative<config_value::dictionary>(entry))
entry = config_value::dictionary{};
auto& submap = get<config_value::dictionary>(entry);
// Flags only consume the current element.
if (opt.is_flag()) {
if (arg_begin != arg_end)
......@@ -223,7 +226,7 @@ auto config_option_set::parse(config_map& config, argument_iterator first,
}
config_option_set::parse_result
config_option_set::parse(config_map& config,
config_option_set::parse(settings& config,
const std::vector<string>& args) const {
return parse(config, args.begin(), args.end());
}
......
......@@ -100,6 +100,17 @@ void config_value::convert_to_list() {
data_ = std::vector<config_value>{std::move(tmp)};
}
config_value::list& config_value::as_list() {
convert_to_list();
return get<list>(*this);
}
config_value::dictionary& config_value::as_dictionary() {
if (!holds_alternative<dictionary>(*this))
*this = dictionary{};
return get<dictionary>(*this);
}
void config_value::append(config_value x) {
convert_to_list();
get<list>(data_).emplace_back(std::move(x));
......@@ -125,81 +136,5 @@ std::string to_string(const config_value& x) {
return deep_to_string(x.get_data());
}
std::string get_or(const config_value::dictionary& xs, const std::string& name,
const char* default_value) {
auto result = get_if<std::string>(&xs, name);
if (result)
return std::move(*result);
return default_value;
}
std::string get_or(const dictionary<config_value::dictionary>& xs,
string_view name, const char* default_value) {
auto result = get_if<std::string>(&xs, name);
if (result)
return std::move(*result);
return default_value;
}
std::string get_or(const actor_system_config& cfg, string_view name,
const char* default_value) {
return get_or(content(cfg), name, default_value);
}
void put_impl(config_value::dictionary& dict,
const std::vector<string_view>& path, config_value& value) {
// Sanity check.
if (path.empty())
return;
// Navigate path.
auto last = path.end();
auto back = last - 1;
auto current = &dict;
// Resolve path by navigating the map-of-maps of create the necessary layout
// when needed.
for (auto i = path.begin(); i != back; ++i) {
auto iter = current->emplace(*i, config_value::dictionary{}).first;
if (auto val = get_if<config_value::dictionary>(&iter->second)) {
current = val;
} else {
iter->second = config_value::dictionary{};
current = &get<config_value::dictionary>(iter->second);
}
}
// Set key-value pair on the leaf.
current->insert_or_assign(*back, std::move(value));
}
void put_impl(config_value::dictionary& dict, string_view key,
config_value& value) {
std::vector<string_view> path;
split(path, key, ".");
put_impl(dict, path, value);
}
void put_impl(dictionary<config_value::dictionary>& dict, string_view key,
config_value& value) {
// Split the name into a path.
std::vector<string_view> path;
split(path, key, ".");
// Sanity check. At the very least, we need a category and a key.
if (path.size() < 2)
return;
auto category = path.front();
path.erase(path.begin());
put_impl(dict[category], path, value);
}
config_value::list& put_list(config_value::dictionary& xs, std::string name) {
auto i = xs.insert_or_assign(std::move(name), config_value::list{});
return get<config_value::list>(i.first->second);
}
config_value::dictionary& put_dictionary(config_value::dictionary& xs,
std::string name) {
auto i = xs.insert_or_assign(std::move(name), config_value::dictionary{});
return get<config_value::dictionary>(i.first->second);
}
} // namespace caf
......@@ -53,7 +53,7 @@ const timespan credit_round_interval = ms(10);
namespace scheduler {
const atom_value policy = atom("stealing");
const char* profiling_output_file = "";
string_view profiling_output_file = "";
const size_t max_threads = std::max(std::thread::hardware_concurrency(), 4u);
const size_t max_throughput = std::numeric_limits<size_t>::max();
const timespan profiling_resolution = ms(100);
......@@ -74,19 +74,19 @@ const timespan relaxed_sleep_duration = ms(10);
namespace logger {
const char* component_filter = "";
string_view component_filter = "";
const atom_value console = atom("none");
const char* console_format = "%m";
string_view console_format = "%m";
const atom_value console_verbosity = atom("trace");
const char* file_format = "%r %c %p %a %t %C %M %F:%L %m%n";
const char* file_name = "actor_log_[PID]_[TIMESTAMP]_[NODE].log";
string_view file_format = "%r %c %p %a %t %C %M %F:%L %m%n";
string_view file_name = "actor_log_[PID]_[TIMESTAMP]_[NODE].log";
const atom_value file_verbosity = atom("trace");
} // namespace logger
namespace middleman {
const char* app_identifier = "";
string_view app_identifier = "";
const atom_value network_backend = atom("default");
const size_t max_consecutive_reads = 50;
const size_t heartbeat_interval = 0;
......
......@@ -153,7 +153,7 @@ ini_consumer* ini_category_consumer::dparent() {
// -- ini_consumer -------------------------------------------------------------
ini_consumer::ini_consumer(config_option_set& options, config_map& cfg)
ini_consumer::ini_consumer(config_option_set& options, settings& cfg)
: options_(options),
cfg_(cfg) {
// nop
......@@ -168,13 +168,15 @@ void ini_consumer::key(std::string name) {
}
void ini_consumer::value_impl(config_value&& x) {
auto dict = get_if<config_value::dictionary>(&x);
if (dict != nullptr && !dict->empty()) {
using dict_type = config_value::dictionary;
auto dict = get_if<dict_type>(&x);
auto& dst = cfg_.emplace(current_key, dict_type{}).first->second;
if (dict != nullptr && !dict->empty() && holds_alternative<dict_type>(dst)) {
auto& dst_dict = get<dict_type>(dst);
// We need to "merge" values into the destination, because it can already
// contain any number of unrelated entries.
auto& dst = cfg_[current_key];
for (auto& entry : *dict)
dst.insert_or_assign(entry.first, std::move(entry.second));
dst_dict.insert_or_assign(entry.first, std::move(entry.second));
}
}
......
......@@ -18,6 +18,7 @@
#include "caf/pec.hpp"
#include "caf/config_value.hpp"
#include "caf/error.hpp"
#include "caf/make_message.hpp"
......@@ -53,9 +54,18 @@ error make_error(pec code) {
}
error make_error(pec code, size_t line, size_t column) {
config_value::dictionary context;
context["line"] = line;
context["column"] = column;
return {static_cast<uint8_t>(code), atom("parser"),
make_message(static_cast<uint32_t>(line),
static_cast<uint32_t>(column))};
make_message(std::move(context))};
}
error make_error(pec code, std::string argument) {
config_value::dictionary context;
context["argument"] = std::move(argument);
return {static_cast<uint8_t>(code), atom("parser"),
make_message(std::move(context))};
}
const char* to_string(pec x) {
......
......@@ -26,6 +26,7 @@
#include "caf/test/dsl.hpp"
#include "caf/config_option_set.hpp"
#include "caf/settings.hpp"
using std::string;
using std::vector;
......@@ -75,7 +76,7 @@ CAF_TEST(parse with ref syncing) {
.add<string>(bar_s, "bar", "s,s", "")
.add<vector<string>>(bar_l, "bar", "l,l", "")
.add<dictionary<string>>(bar_d, "bar", "d,d", "");
dictionary<config_value::dictionary> cfg;
settings cfg;
vector<string> args{"-i42",
"-f",
"1e12",
......@@ -103,7 +104,7 @@ CAF_TEST(parse with ref syncing) {
CAF_TEST(implicit global) {
opts.add<int>("value", "some value").add<bool>("help", "print help text");
CAF_MESSAGE("test long option with argument");
dictionary<config_value::dictionary> cfg;
settings cfg;
auto res = opts.parse(cfg, {"--value=42"});
CAF_CHECK_EQUAL(res.first, pec::success);
CAF_CHECK_EQUAL(get_if<int>(&cfg, "global.value"), 42);
......@@ -118,7 +119,7 @@ CAF_TEST(atom parameters) {
opts.add<atom_value>("value,v", "some value");
CAF_MESSAGE("test atom option without quotes");
auto parse_args = [&](std::vector<std::string> args) -> expected<atom_value> {
dictionary<config_value::dictionary> cfg;
settings cfg;
auto res = opts.parse(cfg, std::move(args));
if (res.first != pec::success)
return res.first;
......
......@@ -250,17 +250,3 @@ CAF_TEST(unsuccessful parsing) {
CAF_CHECK_EQUAL(parse("{a=1,"), pec::unexpected_eof);
CAF_CHECK_EQUAL(parse("{a=1 b=2}"), pec::unexpected_character);
}
CAF_TEST(put values) {
using v = config_value;
using d = config_value::dictionary;
using dd = caf::dictionary<d>;
dd content;
put(content, "a.b", 42);
CAF_CHECK_EQUAL(content, dd({{"a", d({{"b", v{42}}})}}));
put(content, "a.b.c", 1);
CAF_CHECK_EQUAL(content, dd({{"a", d({{"b", v{d({{"c", v{1}}})}}})}}));
put(content, "a.b.d", 2);
CAF_CHECK_EQUAL(content,
dd({{"a", d({{"b", v{d({{"c", v{1}}, {"d", v{2}}})}}})}}));
}
......@@ -48,7 +48,7 @@ impl = 'foo';some atom
struct fixture {
detail::parser::state<std::string::const_iterator> res;
config_option_set options;
config_option_set::config_map config;
settings config;
fixture() {
options.add<bool>("global", "is_server", "enables server mode")
......
......@@ -532,9 +532,16 @@ struct fixture {
return *static_cast<entity*>(actor_cast<abstract_actor*>(hdl));
}
static actor_system_config& init_config(actor_system_config& cfg) {
if (auto err = cfg.parse(caf::test::engine::argc(),
caf::test::engine::argv()))
CAF_FAIL("parsing the config failed: " << to_string(err));
cfg.set("scheduler.policy", caf::atom("testing"));
return cfg;
}
fixture()
: sys(cfg.parse(caf::test::engine::argc(), caf::test::engine::argv())
.set("scheduler.policy", caf::atom("testing"))),
: sys(init_config(cfg)),
sched(dynamic_cast<scheduler_type&>(sys.scheduler())),
alice_hdl(spawn(sys, 0, "alice", tc)),
bob_hdl(spawn(sys, 1, "bob", tc)),
......
......@@ -41,10 +41,7 @@ struct dummy_thread_hook : thread_hook {
}
void thread_started() override {
void* array[20]; \
auto caf_bt_size = ::backtrace(array, 20); \
std::unique_lock<std::mutex> guard{mx};
::backtrace_symbols_fd(array, caf_bt_size, 2); \
// nop
}
void thread_terminates() override {
......
......@@ -20,9 +20,10 @@
#include <algorithm>
#include "caf/logger.hpp"
#include "caf/defaults.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/config_value.hpp"
#include "caf/defaults.hpp"
#include "caf/logger.hpp"
#include "caf/io/network/default_multiplexer.hpp"
......
......@@ -20,11 +20,11 @@
#include <algorithm>
#include "caf/logger.hpp"
#include "caf/defaults.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/config_value.hpp"
#include "caf/defaults.hpp"
#include "caf/io/network/default_multiplexer.hpp"
#include "caf/logger.hpp"
namespace caf {
namespace io {
......
......@@ -148,7 +148,10 @@ behavior peer_acceptor_fun(broker* self, const actor& buddy) {
void run_client(int argc, char** argv, uint16_t port) {
actor_system_config cfg;
actor_system system{cfg.load<io::middleman>().parse(argc, argv)};
cfg.load<io::middleman>();
if (auto err = cfg.parse(argc, argv))
CAF_FAIL("failed to parse config: " << to_string(err));
actor_system system{cfg};
auto p = system.spawn(ping, size_t{10});
CAF_MESSAGE("spawn_client...");
auto cl = unbox(system.middleman().spawn_client(peer_fun,
......@@ -160,7 +163,10 @@ void run_client(int argc, char** argv, uint16_t port) {
void run_server(int argc, char** argv) {
actor_system_config cfg;
actor_system system{cfg.load<io::middleman>().parse(argc, argv)};
cfg.load<io::middleman>();
if (auto err = cfg.parse(argc, argv))
CAF_FAIL("failed to parse config: " << to_string(err));
actor_system system{cfg};
scoped_actor self{system};
CAF_MESSAGE("spawn peer acceptor");
auto serv = system.middleman().spawn_broker(peer_acceptor_fun,
......
......@@ -40,6 +40,8 @@ public:
config() {
load<io::middleman>();
add_message_type<std::vector<int>>("std::vector<int>");
if (auto err = parse(test::engine::argc(), test::engine::argv()))
CAF_FAIL("failed to parse config: " << to_string(err));
}
};
......@@ -55,11 +57,9 @@ struct fixture {
io::middleman& client_side_mm;
fixture()
: server_side(server_side_config.parse(test::engine::argc(),
test::engine::argv())),
: server_side(server_side_config),
server_side_mm(server_side.middleman()),
client_side(client_side_config.parse(test::engine::argc(),
test::engine::argv())),
client_side(client_side_config),
client_side_mm(client_side.middleman()) {
// nop
}
......
......@@ -41,6 +41,8 @@ public:
load<io::middleman>();
set("middleman.enable-udp", true);
add_message_type<std::vector<int>>("std::vector<int>");
if (auto err = parse(test::engine::argc(), test::engine::argv()))
CAF_FAIL("failed to parse config: " << to_string(err));
}
};
......@@ -56,11 +58,9 @@ struct fixture {
io::middleman& client_side_mm;
fixture()
: server_side(server_side_config.parse(test::engine::argc(),
test::engine::argv())),
: server_side(server_side_config),
server_side_mm(server_side.middleman()),
client_side(client_side_config.parse(test::engine::argc(),
test::engine::argv())),
client_side(client_side_config),
client_side_mm(client_side.middleman()) {
// nop
}
......
......@@ -164,7 +164,10 @@ acceptor::behavior_type acceptor_fun(acceptor::broker_pointer self,
void run_client(int argc, char** argv, uint16_t port) {
actor_system_config cfg;
actor_system system{cfg.load<io::middleman>().parse(argc, argv)};
cfg.load<io::middleman>();
if (auto err = cfg.parse(argc, argv))
CAF_FAIL("failed to parse config: " << to_string(err));
actor_system system{cfg};
auto p = system.spawn(ping, size_t{10});
CAF_MESSAGE("spawn_client_typed...");
auto cl = unbox(system.middleman().spawn_client(peer_fun,
......@@ -176,7 +179,10 @@ void run_client(int argc, char** argv, uint16_t port) {
void run_server(int argc, char** argv) {
actor_system_config cfg;
actor_system system{cfg.load<io::middleman>().parse(argc, argv)};
cfg.load<io::middleman>();
if (auto err = cfg.parse(argc, argv))
CAF_FAIL("failed to parse config: " << to_string(err));
actor_system system{cfg};
scoped_actor self{system};
auto serv = system.middleman().spawn_broker(acceptor_fun, system.spawn(pong));
std::thread child;
......@@ -199,7 +205,5 @@ void run_server(int argc, char** argv) {
} // namespace <anonymous>
CAF_TEST(test_typed_broker) {
auto argc = test::engine::argc();
auto argv = test::engine::argv();
run_server(argc, argv);
run_server(test::engine::argc(), test::engine::argv());
}
......@@ -77,8 +77,9 @@ void run_client(int argc, char** argv, uint16_t port) {
actor_system_config cfg;
cfg.load<io::middleman>()
.add_message_type<ping>("ping")
.add_message_type<pong>("pong")
.parse(argc, argv);
.add_message_type<pong>("pong");
if (auto err = cfg.parse(argc, argv))
CAF_FAIL("failed to parse config: " << to_string(err));
actor_system sys{cfg};
// check whether invalid_argument is thrown
// when trying to connect to get an untyped
......
......@@ -53,11 +53,17 @@ public:
}
};
struct config : actor_system_config {
config() {
load<io::middleman>();
if (auto err = parse(test::engine::argc(), test::engine::argv()))
CAF_FAIL("failed to parse config: " << to_string(err));
}
};
struct fixture {
fixture() {
new (&system) actor_system(cfg.load<io::middleman>()
.parse(test::engine::argc(),
test::engine::argv()));
new (&system) actor_system(cfg);
testee = system.spawn<dummy>();
}
......@@ -90,7 +96,7 @@ struct fixture {
return result;
}
actor_system_config cfg;
config cfg;
union { actor_system system; }; // manually control ctor/dtor
actor testee;
};
......
......@@ -556,13 +556,20 @@ public:
// -- constructors, destructors, and assignment operators --------------------
static Config& init_config(Config& cfg) {
if (auto err = cfg.parse(caf::test::engine::argc(),
caf::test::engine::argv()))
CAF_FAIL("failed to parse config: " << to_string(err));
cfg.set("scheduler.policy", caf::atom("testing"));
cfg.set("logger.inline-output", true);
cfg.set("middleman.network-backend", caf::atom("testing"));
return cfg;
}
template <class... Ts>
explicit test_coordinator_fixture(Ts&&... xs)
: cfg(std::forward<Ts>(xs)...),
sys(cfg.parse(caf::test::engine::argc(), caf::test::engine::argv())
.set("scheduler.policy", caf::atom("testing"))
.set("logger.inline-output", true)
.set("middleman.network-backend", caf::atom("testing"))),
sys(init_config(cfg)),
self(sys, true),
sched(dynamic_cast<scheduler_type&>(sys.scheduler())) {
// Configure the clock to measure each batch item with 1us.
......
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