Commit 88a78a43 authored by Dominik Charousset's avatar Dominik Charousset

Merge pull request #702

parents b65378b5 11e0d02b
...@@ -12,7 +12,7 @@ max-threads=<number of cores> ...@@ -12,7 +12,7 @@ max-threads=<number of cores>
; maximum number of messages actors can consume in one run ; maximum number of messages actors can consume in one run
max-throughput=<infinite> max-throughput=<infinite>
; measurement resolution in milliseconds (only if profiling is enabled) ; measurement resolution in milliseconds (only if profiling is enabled)
profiling-ms-resolution=100 profiling-resolution=100ms
; output file for profiler data (only if profiling is enabled) ; output file for profiler data (only if profiling is enabled)
profiling-output-file="/dev/null" profiling-output-file="/dev/null"
...@@ -26,12 +26,12 @@ aggressive-steal-interval=10 ...@@ -26,12 +26,12 @@ aggressive-steal-interval=10
moderate-poll-attempts=500 moderate-poll-attempts=500
; frequency of steal attempts during moderate polling ; frequency of steal attempts during moderate polling
moderate-steal-interval=5 moderate-steal-interval=5
; sleep interval in microseconds between poll attempts ; sleep interval between poll attempts
moderate-sleep-duration=50 moderate-sleep-duration=50us
; frequency of steal attempts during relaxed polling ; frequency of steal attempts during relaxed polling
relaxed-steal-interval=1 relaxed-steal-interval=1
; sleep interval in microseconds between poll attempts ; sleep interval between poll attempts
relaxed-sleep-duration=10000 relaxed-sleep-duration=10ms
; when loading io::middleman ; when loading io::middleman
[middleman] [middleman]
...@@ -45,17 +45,18 @@ app-identifier="" ...@@ -45,17 +45,18 @@ app-identifier=""
; maximum number of consecutive I/O reads per broker ; maximum number of consecutive I/O reads per broker
max-consecutive-reads=50 max-consecutive-reads=50
; heartbeat message interval in ms (0 disables heartbeating) ; heartbeat message interval in ms (0 disables heartbeating)
heartbeat-interval=0 heartbeat-interval=0ms
; configures whether the MM detaches its internal utility actors, setting ; configures whether the MM attaches its internal utility actors to the
; this to false allows fully deterministic execution in unit tests ; scheduler instead of dedicating individual threads (needed only for
detach-utility-actors=true ; deterministic testing)
attach-utility-actors=false
; configures whether the MM starts a background thread for I/O activity, ; configures whether the MM starts a background thread for I/O activity,
; setting this to false allows fully deterministic execution in unit test and ; setting this to true allows fully deterministic execution in unit test and
; requires the user to trigger I/O manually ; requires the user to trigger I/O manually
detach-multiplexer=true manual-multiplexing=false
; enable or disable communication via the TCP transport protocol ; disables communication via TCP
enable-tcp=true disable-tcp=false
; enable or disable communication via the UDP transport protocol ; enable communication via UDP
enable-udp=false enable-udp=false
; when compiling with logging enabled ; when compiling with logging enabled
......
...@@ -37,8 +37,12 @@ set(LIBCAF_CORE_SRCS ...@@ -37,8 +37,12 @@ set(LIBCAF_CORE_SRCS
src/blocking_behavior.cpp src/blocking_behavior.cpp
src/concatenated_tuple.cpp src/concatenated_tuple.cpp
src/config_option.cpp src/config_option.cpp
src/config_option_adder.cpp
src/config_option_set.cpp
src/config_value.cpp
src/decorated_tuple.cpp src/decorated_tuple.cpp
src/default_attachable.cpp src/default_attachable.cpp
src/defaults.cpp
src/deserializer.cpp src/deserializer.cpp
src/downstream_manager.cpp src/downstream_manager.cpp
src/downstream_manager_base.cpp src/downstream_manager_base.cpp
...@@ -50,6 +54,7 @@ set(LIBCAF_CORE_SRCS ...@@ -50,6 +54,7 @@ set(LIBCAF_CORE_SRCS
src/execution_unit.cpp src/execution_unit.cpp
src/exit_reason.cpp src/exit_reason.cpp
src/forwarding_actor_proxy.cpp src/forwarding_actor_proxy.cpp
src/fsm.cpp
src/get_mac_addresses.cpp src/get_mac_addresses.cpp
src/get_process_id.cpp src/get_process_id.cpp
src/get_root_uuid.cpp src/get_root_uuid.cpp
...@@ -57,10 +62,12 @@ set(LIBCAF_CORE_SRCS ...@@ -57,10 +62,12 @@ set(LIBCAF_CORE_SRCS
src/group_manager.cpp src/group_manager.cpp
src/group_module.cpp src/group_module.cpp
src/inbound_path.cpp src/inbound_path.cpp
src/ini_consumer.cpp
src/invoke_result_visitor.cpp src/invoke_result_visitor.cpp
src/local_actor.cpp src/local_actor.cpp
src/logger.cpp src/logger.cpp
src/mailbox_element.cpp src/mailbox_element.cpp
src/make_config_option.cpp
src/match_case.cpp src/match_case.cpp
src/memory_managed.cpp src/memory_managed.cpp
src/merged_tuple.cpp src/merged_tuple.cpp
...@@ -72,7 +79,7 @@ set(LIBCAF_CORE_SRCS ...@@ -72,7 +79,7 @@ set(LIBCAF_CORE_SRCS
src/monitorable_actor.cpp src/monitorable_actor.cpp
src/node_id.cpp src/node_id.cpp
src/outbound_path.cpp src/outbound_path.cpp
src/parse_ini.cpp src/pec.cpp
src/pretty_type_name.cpp src/pretty_type_name.cpp
src/private_thread.cpp src/private_thread.cpp
src/proxy_registry.cpp src/proxy_registry.cpp
......
...@@ -26,15 +26,16 @@ ...@@ -26,15 +26,16 @@
#include <type_traits> #include <type_traits>
#include <unordered_map> #include <unordered_map>
#include "caf/actor_factory.hpp"
#include "caf/config_option.hpp"
#include "caf/config_option_set.hpp"
#include "caf/config_value.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/is_typed_actor.hpp"
#include "caf/named_actor_config.hpp"
#include "caf/stream.hpp" #include "caf/stream.hpp"
#include "caf/thread_hook.hpp" #include "caf/thread_hook.hpp"
#include "caf/config_value.hpp"
#include "caf/config_option.hpp"
#include "caf/actor_factory.hpp"
#include "caf/is_typed_actor.hpp"
#include "caf/type_erased_value.hpp" #include "caf/type_erased_value.hpp"
#include "caf/named_actor_config.hpp"
#include "caf/detail/safe_equal.hpp" #include "caf/detail/safe_equal.hpp"
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
...@@ -74,32 +75,17 @@ public: ...@@ -74,32 +75,17 @@ public:
using error_renderer_map = hash_map<atom_value, error_renderer>; using error_renderer_map = hash_map<atom_value, error_renderer>;
using option_ptr = std::unique_ptr<config_option>;
using option_vector = std::vector<option_ptr>;
using group_module_factory = std::function<group_module* ()>; using group_module_factory = std::function<group_module* ()>;
using group_module_factory_vector = std::vector<group_module_factory>; using group_module_factory_vector = std::vector<group_module_factory>;
// -- nested classes --------------------------------------------------------- using config_map = std::map<std::string, config_value::dictionary>;
using named_actor_config_map = hash_map<std::string, named_actor_config>; using string_list = std::vector<std::string>;
class opt_group { using named_actor_config_map = hash_map<std::string, named_actor_config>;
public:
opt_group(option_vector& xs, const char* category);
template <class T>
opt_group& add(T& storage, const char* name, const char* explanation) {
xs_.emplace_back(make_config_option(storage, cat_, name, explanation));
return *this;
}
private: using opt_group = config_option_adder;
option_vector& xs_;
const char* cat_;
};
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
...@@ -112,18 +98,29 @@ public: ...@@ -112,18 +98,29 @@ public:
actor_system_config(const actor_system_config&) = delete; actor_system_config(const actor_system_config&) = delete;
actor_system_config& operator=(const actor_system_config&) = delete; actor_system_config& operator=(const actor_system_config&) = delete;
// -- properties -------------------------------------------------------------
/// @private
std::map<std::string, config_value::dictionary> content;
/// Sets a config by using its INI name `config_name` to `config_value`.
template <class T>
actor_system_config& set(const char* name, T&& value) {
return set_impl(name, config_value{std::forward<T>(value)});
}
// -- modifiers -------------------------------------------------------------- // -- 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 tries to /// 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 `ini_file_cstr` as INI formatted config file. The parsers tries to
/// open `caf-application.ini` if `ini_file_cstr` is `nullptr`. /// open `caf-application.ini` if `ini_file_cstr` is `nullptr`.
actor_system_config& parse(message& args, actor_system_config& parse(string_list args,
const char* ini_file_cstr = nullptr); const char* ini_file_cstr = nullptr);
/// Parses `args` as tuple of strings containing CLI options
/// and `ini_stream` as INI formatted input stream.
actor_system_config& parse(message& args, std::istream& ini);
/// Parses the CLI options `{argc, argv}` and /// Parses the CLI options `{argc, argv}` and
/// `ini_stream` as INI formatted input stream. /// `ini_stream` as INI formatted input stream.
actor_system_config& parse(int argc, char** argv, std::istream& ini); actor_system_config& parse(int argc, char** argv, std::istream& ini);
...@@ -134,6 +131,11 @@ public: ...@@ -134,6 +131,11 @@ public:
actor_system_config& parse(int argc, char** argv, actor_system_config& parse(int argc, char** argv,
const char* ini_file_cstr = nullptr); const char* ini_file_cstr = nullptr);
actor_system_config&
parse(message& args, const char* ini_file_cstr = nullptr) CAF_DEPRECATED;
actor_system_config& parse(message& args, std::istream& ini) CAF_DEPRECATED;
/// Allows other nodes to spawn actors created by `fun` /// Allows other nodes to spawn actors created by `fun`
/// dynamically by using `name` as identifier. /// dynamically by using `name` as identifier.
/// @experimental /// @experimental
...@@ -237,9 +239,6 @@ public: ...@@ -237,9 +239,6 @@ public:
return *this; return *this;
} }
/// Sets a config by using its INI name `config_name` to `config_value`.
actor_system_config& set(const char* cn, config_value cv);
// -- parser and CLI state --------------------------------------------------- // -- parser and CLI state ---------------------------------------------------
/// Stores whether the help text was printed. If set to `true`, the /// Stores whether the help text was printed. If set to `true`, the
...@@ -248,7 +247,10 @@ public: ...@@ -248,7 +247,10 @@ public:
bool cli_helptext_printed; bool cli_helptext_printed;
/// Stores CLI arguments that were not consumed by CAF. /// Stores CLI arguments that were not consumed by CAF.
message args_remainder; message args_remainder CAF_DEPRECATED;
/// Stores CLI arguments that were not consumed by CAF.
string_list remainder;
// -- caf-run parameters ----------------------------------------------------- // -- caf-run parameters -----------------------------------------------------
...@@ -302,46 +304,44 @@ public: ...@@ -302,46 +304,44 @@ public:
// -- scheduling parameters -------------------------------------------------- // -- scheduling parameters --------------------------------------------------
atom_value scheduler_policy; atom_value scheduler_policy CAF_DEPRECATED;
size_t scheduler_max_threads; size_t scheduler_max_threads CAF_DEPRECATED;
size_t scheduler_max_throughput; size_t scheduler_max_throughput CAF_DEPRECATED;
bool scheduler_enable_profiling; bool scheduler_enable_profiling CAF_DEPRECATED;
size_t scheduler_profiling_ms_resolution; size_t scheduler_profiling_ms_resolution CAF_DEPRECATED;
std::string scheduler_profiling_output_file; std::string scheduler_profiling_output_file CAF_DEPRECATED;
// -- work-stealing parameters ----------------------------------------------- // -- work-stealing parameters -----------------------------------------------
size_t work_stealing_aggressive_poll_attempts; size_t work_stealing_aggressive_poll_attempts CAF_DEPRECATED;
size_t work_stealing_aggressive_steal_interval; size_t work_stealing_aggressive_steal_interval CAF_DEPRECATED;
size_t work_stealing_moderate_poll_attempts; size_t work_stealing_moderate_poll_attempts CAF_DEPRECATED;
size_t work_stealing_moderate_steal_interval; size_t work_stealing_moderate_steal_interval CAF_DEPRECATED;
size_t work_stealing_moderate_sleep_duration_us; size_t work_stealing_moderate_sleep_duration_us CAF_DEPRECATED;
size_t work_stealing_relaxed_steal_interval; size_t work_stealing_relaxed_steal_interval CAF_DEPRECATED;
size_t work_stealing_relaxed_sleep_duration_us; size_t work_stealing_relaxed_sleep_duration_us CAF_DEPRECATED;
// -- logger parameters ------------------------------------------------------ // -- logger parameters ------------------------------------------------------
std::string logger_file_name; std::string logger_file_name CAF_DEPRECATED;
std::string logger_file_format; std::string logger_file_format CAF_DEPRECATED;
atom_value logger_console; atom_value logger_console CAF_DEPRECATED;
std::string logger_console_format; std::string logger_console_format CAF_DEPRECATED;
std::string logger_component_filter; std::string logger_component_filter CAF_DEPRECATED;
atom_value logger_verbosity; atom_value logger_verbosity CAF_DEPRECATED;
bool logger_inline_output; bool logger_inline_output CAF_DEPRECATED;
// -- middleman parameters --------------------------------------------------- // -- middleman parameters ---------------------------------------------------
atom_value middleman_network_backend; atom_value middleman_network_backend CAF_DEPRECATED;
std::string middleman_app_identifier; std::string middleman_app_identifier CAF_DEPRECATED;
bool middleman_enable_automatic_connections; bool middleman_enable_automatic_connections CAF_DEPRECATED;
size_t middleman_max_consecutive_reads; size_t middleman_max_consecutive_reads CAF_DEPRECATED;
size_t middleman_heartbeat_interval; size_t middleman_heartbeat_interval CAF_DEPRECATED;
bool middleman_detach_utility_actors; bool middleman_detach_utility_actors CAF_DEPRECATED;
bool middleman_detach_multiplexer; bool middleman_detach_multiplexer CAF_DEPRECATED;
bool middleman_enable_tcp; size_t middleman_cached_udp_buffers CAF_DEPRECATED;
bool middleman_enable_udp; size_t middleman_max_pending_msgs CAF_DEPRECATED;
size_t middleman_cached_udp_buffers;
size_t middleman_max_pending_msgs;
// -- OpenCL parameters ------------------------------------------------------ // -- OpenCL parameters ------------------------------------------------------
...@@ -382,16 +382,6 @@ public: ...@@ -382,16 +382,6 @@ public:
/// default. /// default.
std::string config_file_path; std::string config_file_path;
// -- convenience functions --------------------------------------------------
template <class F>
void for_each_option(F f) const {
const option_vector* all_options[] = { &options_, &custom_options_ };
for (auto& opt_vec : all_options)
for (auto& opt : *opt_vec)
f(*opt);
}
// -- utility for caf-run ---------------------------------------------------- // -- utility for caf-run ----------------------------------------------------
// Config parameter for individual actor types. // Config parameter for individual actor types.
...@@ -402,7 +392,7 @@ public: ...@@ -402,7 +392,7 @@ public:
protected: protected:
virtual std::string make_help_text(const std::vector<message::cli_arg>&); virtual std::string make_help_text(const std::vector<message::cli_arg>&);
option_vector custom_options_; config_option_set custom_options_;
private: private:
template <class T> template <class T>
...@@ -413,13 +403,13 @@ private: ...@@ -413,13 +403,13 @@ private:
&make_type_erased_value<T>); &make_type_erased_value<T>);
} }
actor_system_config& set_impl(const char* name, config_value value);
static std::string render_sec(uint8_t, atom_value, const message&); static std::string render_sec(uint8_t, atom_value, const message&);
static std::string render_exit_reason(uint8_t, atom_value, const message&); static std::string render_exit_reason(uint8_t, atom_value, const message&);
void extract_config_file_path(message& args); void extract_config_file_path(string_list& args);
option_vector options_;
}; };
} // namespace caf } // namespace caf
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include "caf/message.hpp" #include "caf/message.hpp"
#include "caf/node_id.hpp" #include "caf/node_id.hpp"
#include "caf/behavior.hpp" #include "caf/behavior.hpp"
#include "caf/defaults.hpp"
#include "caf/duration.hpp" #include "caf/duration.hpp"
#include "caf/expected.hpp" #include "caf/expected.hpp"
#include "caf/exec_main.hpp" #include "caf/exec_main.hpp"
...@@ -59,10 +60,12 @@ ...@@ -59,10 +60,12 @@
#include "caf/typed_actor.hpp" #include "caf/typed_actor.hpp"
#include "caf/stream_slot.hpp" #include "caf/stream_slot.hpp"
#include "caf/actor_system.hpp" #include "caf/actor_system.hpp"
#include "caf/config_value.hpp"
#include "caf/deserializer.hpp" #include "caf/deserializer.hpp"
#include "caf/scoped_actor.hpp" #include "caf/scoped_actor.hpp"
#include "caf/upstream_msg.hpp" #include "caf/upstream_msg.hpp"
#include "caf/actor_ostream.hpp" #include "caf/actor_ostream.hpp"
#include "caf/config_option.hpp"
#include "caf/function_view.hpp" #include "caf/function_view.hpp"
#include "caf/index_mapping.hpp" #include "caf/index_mapping.hpp"
#include "caf/spawn_options.hpp" #include "caf/spawn_options.hpp"
...@@ -89,10 +92,12 @@ ...@@ -89,10 +92,12 @@
#include "caf/composed_behavior.hpp" #include "caf/composed_behavior.hpp"
#include "caf/event_based_actor.hpp" #include "caf/event_based_actor.hpp"
#include "caf/primitive_variant.hpp" #include "caf/primitive_variant.hpp"
#include "caf/make_config_option.hpp"
#include "caf/timeout_definition.hpp" #include "caf/timeout_definition.hpp"
#include "caf/actor_system_config.hpp" #include "caf/actor_system_config.hpp"
#include "caf/binary_deserializer.hpp" #include "caf/binary_deserializer.hpp"
#include "caf/composable_behavior.hpp" #include "caf/composable_behavior.hpp"
#include "caf/config_option_adder.hpp"
#include "caf/typed_actor_pointer.hpp" #include "caf/typed_actor_pointer.hpp"
#include "caf/scoped_execution_unit.hpp" #include "caf/scoped_execution_unit.hpp"
#include "caf/typed_response_promise.hpp" #include "caf/typed_response_promise.hpp"
......
...@@ -96,6 +96,9 @@ ...@@ -96,6 +96,9 @@
# define CAF_PUSH_NON_VIRTUAL_DTOR_WARNING \ # define CAF_PUSH_NON_VIRTUAL_DTOR_WARNING \
_Pragma("clang diagnostic push") \ _Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wnon-virtual-dtor\"") _Pragma("clang diagnostic ignored \"-Wnon-virtual-dtor\"")
# define CAF_PUSH_DEPRECATED_WARNING \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"")
# define CAF_POP_WARNINGS \ # define CAF_POP_WARNINGS \
_Pragma("clang diagnostic pop") _Pragma("clang diagnostic pop")
# define CAF_ANNOTATE_FALLTHROUGH [[clang::fallthrough]] # define CAF_ANNOTATE_FALLTHROUGH [[clang::fallthrough]]
...@@ -122,6 +125,9 @@ ...@@ -122,6 +125,9 @@
# define CAF_PUSH_NON_VIRTUAL_DTOR_WARNING \ # define CAF_PUSH_NON_VIRTUAL_DTOR_WARNING \
_Pragma("GCC diagnostic push") \ _Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wnon-virtual-dtor\"") _Pragma("GCC diagnostic ignored \"-Wnon-virtual-dtor\"")
# define CAF_PUSH_DEPRECATED_WARNING \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
# define CAF_POP_WARNINGS \ # define CAF_POP_WARNINGS \
_Pragma("GCC diagnostic pop") _Pragma("GCC diagnostic pop")
# define CAF_ANNOTATE_FALLTHROUGH static_cast<void>(0) # define CAF_ANNOTATE_FALLTHROUGH static_cast<void>(0)
...@@ -154,6 +160,8 @@ ...@@ -154,6 +160,8 @@
# define CAF_UNLIKELY(x) x # define CAF_UNLIKELY(x) x
# define CAF_DEPRECATED # define CAF_DEPRECATED
# define CAF_PUSH_WARNINGS # define CAF_PUSH_WARNINGS
# define CAF_PUSH_NON_VIRTUAL_DTOR_WARNING
# define CAF_PUSH_DEPRECATED_WARNING
# define CAF_POP_WARNINGS # define CAF_POP_WARNINGS
# define CAF_ANNOTATE_FALLTHROUGH static_cast<void>(0) # define CAF_ANNOTATE_FALLTHROUGH static_cast<void>(0)
#endif #endif
......
This diff is collapsed.
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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 <vector>
#include "caf/config_option.hpp"
#include "caf/fwd.hpp"
namespace caf {
/// Adds config options of the same category to a `config_option_set`.
class config_option_adder {
public:
// -- constructors, destructors, and assignment operators --------------------
config_option_adder(config_option_set& target, const char* category);
// -- properties -------------------------------------------------------------
/// Adds a config option to the category that synchronizes with `ref`.
template <class T>
config_option_adder& add(T& ref, const char* name, const char* description) {
return add_impl(make_config_option(ref, category_, name, description));
}
/// Adds a config option to the category.
template <class T>
config_option_adder& add(const char* name, const char* description) {
return add_impl(make_config_option<T>(category_, name, description));
}
/// For backward compatibility only. Do not use for new code!
/// @private
config_option_adder& add_neg(bool& ref, const char* name,
const char* description);
/// For backward compatibility only. Do not use for new code!
/// @private
config_option_adder& add_us(size_t& ref, const char* name,
const char* description);
/// For backward compatibility only. Do not use for new code!
/// @private
config_option_adder& add_ms(size_t& ref, const char* name,
const char* description);
private:
// -- properties -------------------------------------------------------------
config_option_adder& add_impl(config_option&& opt);
// -- member variables -------------------------------------------------------
/// Reference to the target set.
config_option_set& xs_;
/// Category for all options generated by this adder.
const char* category_;
};
} // 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. *
******************************************************************************/
#pragma once
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "caf/config_option.hpp"
#include "caf/fwd.hpp"
#include "caf/make_config_option.hpp"
#include "caf/pec.hpp"
namespace caf {
/// A set of `config_option` objects that parses CLI arguments into a
/// `config_value::dictionary`.
class config_option_set {
public:
// -- member types -----------------------------------------------------------
/// An iterator over CLI arguments.
using argument_iterator = std::vector<std::string>::const_iterator;
/// The result of `parse` member functions.
using parse_result = std::pair<pec, argument_iterator>;
/// List of config options.
using option_vector = std::vector<config_option>;
/// Pointer to a config option.
using option_pointer = const config_option*;
/// An iterator over ::config_option unique pointers.
using iterator = option_vector::iterator;
/// Maps string keys to arbitrary (config) values.
using dictionary = std::map<std::string, config_value>;
/// Categorized settings.
using config_map = std::map<std::string, dictionary>;
// -- constructors, destructors, and assignment operators --------------------
config_option_set();
// -- properties -------------------------------------------------------------
/// Returns the first `config_option` that matches the CLI name.
/// @param name Config option name formatted as
/// `<prefix>#<category>.<long-name>`. Users can omit `<prefix>`
/// for options that have an empty prefix and `<category>`
/// if the category is "global".
option_pointer cli_long_name_lookup(const std::string& name) const;
/// Returns the first `config_option` that matches the CLI short option name.
option_pointer cli_short_name_lookup(char short_name) const;
/// Returns the first `config_option` that matches category and long name.
option_pointer qualified_name_lookup(const std::string& category,
const std::string& long_name) const;
/// Returns the first `config_option` that matches the qualified name.
/// @param name Config option name formatted as `<category>.<long-name>`.
option_pointer qualified_name_lookup(const std::string& name) const;
/// Returns the number of stored config options.
inline size_t size() const noexcept {
return opts_.size();
}
/// Returns an iterator to the first ::config_option object.
inline iterator begin() noexcept {
return opts_.begin();
}
/// Returns the past-the-end iterator.
inline iterator end() noexcept {
return opts_.end();
}
/// Adds a config option to the set.
template <class T>
config_option_set& add(const char* category, const char* name,
const char* description = "") {
return add(make_config_option<T>(category, name, description));
}
/// Adds a config option to the set that synchronizes its value with `ref`.
template <class T>
config_option_set& add(T& ref, const char* category, const char* name,
const char* description = "") {
return add(make_config_option<T>(ref, category, name, description));
}
/// Adds a config option to the set.
/// @private
config_option_set& add(config_option&& opt);
/// Generates human-readable help text for all options.
std::string help_text(bool global_only = true) const;
// -- parsing ----------------------------------------------------------------
/// Parses a given range as CLI arguments into `config`.
parse_result parse(config_map& config, argument_iterator begin,
argument_iterator end) const;
/// Parses a given range as CLI arguments into `config`.
parse_result parse(config_map& config,
const std::vector<std::string>& args) const;
private:
// -- member variables -------------------------------------------------------
option_vector opts_;
};
} // namespace caf
This diff is collapsed.
...@@ -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 {
...@@ -38,21 +39,29 @@ struct default_sum_type_access { ...@@ -38,21 +39,29 @@ struct default_sum_type_access {
static constexpr bool immutable = false; static constexpr bool immutable = false;
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>
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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 <chrono>
#include <cstddef>
#include "caf/atom.hpp"
#include "caf/timestamp.hpp"
// -- hard-coded default values for various CAF options ------------------------
namespace caf {
namespace defaults {
namespace streaming {
extern const timespan desired_batch_complexity;
extern const timespan max_batch_delay;
extern const timespan credit_round_interval;
} // namespace streaming
namespace scheduler {
extern const atom_value policy;
extern const char* profiling_output_file;
extern const size_t max_threads;
extern const size_t max_throughput;
extern const timespan profiling_resolution;
} // namespace scheduler
namespace work_stealing {
extern const size_t aggressive_poll_attempts;
extern const size_t aggressive_steal_interval;
extern const size_t moderate_poll_attempts;
extern const size_t moderate_steal_interval;
extern const timespan moderate_sleep_duration;
extern const size_t relaxed_steal_interval;
extern const timespan relaxed_sleep_duration;
} // namespace work_stealing
namespace logger {
extern const atom_value console;
extern const atom_value verbosity;
extern const char* component_filter;
extern const char* console_format;
extern const char* file_format;
extern const char* file_name;
} // namespace logger
namespace middleman {
extern const char* app_identifier;
extern const atom_value network_backend;
extern const size_t max_consecutive_reads;
extern const size_t heartbeat_interval;
extern const size_t cached_udp_buffers;
extern const size_t max_pending_msgs;
} // namespace middleman
} // namespace defaults
} // namespace caf
...@@ -85,6 +85,49 @@ container_view<F, Container> make_container_view(Container& x) { ...@@ -85,6 +85,49 @@ container_view<F, Container> make_container_view(Container& x) {
return {x}; return {x};
} }
/// Like `std::find`, but takes a range instead of an iterator pair and returns
/// a pointer to the found object on success instead of returning an iterator.
template <class T>
typename T::value_type* ptr_find(T& xs, const typename T::value_type& x) {
for (auto& y : xs)
if (y == x)
return &y;
return nullptr;
}
/// Like `std::find`, but takes a range instead of an iterator pair and returns
/// a pointer to the found object on success instead of returning an iterator.
template <class T>
const typename T::value_type* ptr_find(const T& xs,
const typename T::value_type& x) {
for (auto& y : xs)
if (y == x)
return &y;
return nullptr;
}
/// Like `std::find_if`, but takes a range instead of an iterator pair and
/// returns a pointer to the found object on success instead of returning an
/// iterator.
template <class T, class Predicate>
typename T::value_type* ptr_find_if(T& xs, Predicate pred) {
for (auto& x : xs)
if (pred(x))
return &x;
return nullptr;
}
/// Like `std::find_if`, but takes a range instead of an iterator pair and
/// returns a pointer to the found object on success instead of returning an
/// iterator.
template <class T, class Predicate>
const typename T::value_type* ptr_find_if(const T& xs, Predicate pred) {
for (auto& x : xs)
if (pred(x))
return &x;
return nullptr;
}
} // namespace detail } // namespace detail
} // namespace caf } // 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. *
******************************************************************************/
#pragma once
#include <cstdint>
#include <limits>
#include <type_traits>
namespace caf {
namespace detail {
template <class To, bool LargeUnsigned = sizeof(To) >= sizeof(int64_t)
&& std::is_unsigned<To>::value>
struct bounds_checker {
static inline bool check(int64_t x) {
return x >= std::numeric_limits<To>::min()
&& x <= std::numeric_limits<To>::max();
}
};
template <class To>
struct bounds_checker<To, true> {
static inline bool check(int64_t x) {
return x >= 0;
}
};
} // namespace detail
} // 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. *
******************************************************************************/
#pragma once
#include <map>
#include <string>
#include "caf/config_option_set.hpp"
#include "caf/config_value.hpp"
namespace caf {
namespace detail {
class ini_consumer;
class ini_list_consumer;
class ini_map_consumer;
class abstract_ini_consumer {
public:
// -- constructors, destructors, and assignment operators --------------------
explicit abstract_ini_consumer(abstract_ini_consumer* parent = nullptr);
virtual ~abstract_ini_consumer();
// -- properties -------------------------------------------------------------
virtual void value_impl(config_value&& x) = 0;
template <class T>
void value(T&& x) {
value_impl(config_value{std::forward<T>(x)});
}
inline abstract_ini_consumer* parent() {
return parent_;
}
ini_map_consumer begin_map();
ini_list_consumer begin_list();
protected:
// -- member variables -------------------------------------------------------
abstract_ini_consumer* parent_;
};
class ini_map_consumer : public abstract_ini_consumer {
public:
// -- member types -----------------------------------------------------------
using super = abstract_ini_consumer;
using map_type = config_value::dictionary;
using iterator = map_type::iterator;
// -- constructors, destructors, and assignment operators --------------------
ini_map_consumer(abstract_ini_consumer* ptr);
ini_map_consumer(ini_map_consumer&& other);
~ini_map_consumer() override;
// -- properties -------------------------------------------------------------
void end_map();
void key(std::string name);
void value_impl(config_value&& x) override;
private:
// -- member variables -------------------------------------------------------
map_type xs_;
iterator i_;
};
class ini_list_consumer : public abstract_ini_consumer {
public:
// -- member types -----------------------------------------------------------
using super = abstract_ini_consumer;
// -- constructors, destructors, and assignment operators --------------------
ini_list_consumer(abstract_ini_consumer* ptr);
ini_list_consumer(ini_list_consumer&& other);
// -- properties -------------------------------------------------------------
void end_list();
void value_impl(config_value&& x) override;
private:
// -- member variables -------------------------------------------------------
config_value::list xs_;
};
/// Consumes a single value from an INI parser.
class ini_value_consumer : public abstract_ini_consumer {
public:
// -- member types -----------------------------------------------------------
using super = abstract_ini_consumer;
// -- constructors, destructors, and assignment operators --------------------
explicit ini_value_consumer(abstract_ini_consumer* parent = nullptr);
// -- properties -------------------------------------------------------------
void value_impl(config_value&& x) override;
// -- member variables -------------------------------------------------------
config_value result;
};
/// Consumes a config category.
class ini_category_consumer : public abstract_ini_consumer {
public:
// -- member types -----------------------------------------------------------
using super = abstract_ini_consumer;
// -- constructors, destructors, and assignment operators --------------------
ini_category_consumer(ini_consumer* parent, std::string category);
ini_category_consumer(ini_category_consumer&&) = default;
// -- properties -------------------------------------------------------------
void end_map();
void key(std::string name);
void value_impl(config_value&& x) override;
private:
// -- properties -------------------------------------------------------------
ini_consumer* dparent();
// -- member variables -------------------------------------------------------
std::string category_;
config_value::dictionary xs_;
std::string current_key;
};
/// Consumes a series of dictionaries forming a application configuration.
class ini_consumer : public abstract_ini_consumer {
public:
// -- friends ----------------------------------------------------------------
friend class ini_category_consumer;
// -- member types -----------------------------------------------------------
using super = abstract_ini_consumer;
using config_map = std::map<std::string, config_value::dictionary>;
// -- constructors, destructors, and assignment operators --------------------
ini_consumer(config_option_set& options, config_map& cfg);
ini_consumer(ini_consumer&&) = default;
// -- properties -------------------------------------------------------------
ini_category_consumer begin_map();
void key(std::string name);
void value_impl(config_value&& x) override;
private:
// -- member variables -------------------------------------------------------
config_option_set& options_;
config_map& cfg_;
std::string current_key;
std::vector<error> warnings_;
};
} // namespace detail
} // 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. *
******************************************************************************/
#pragma once
#include <type_traits>
namespace caf {
namespace detail {
/// Checks wheter `T` is in the template parameter pack `Ts`.
template <class T, class... Ts>
struct is_one_of;
template <class T>
struct is_one_of<T> : std::false_type {};
template <class T, class... Ts>
struct is_one_of<T, T, Ts...> : std::true_type {};
template <class T, class U, class... Ts>
struct is_one_of<T, U, Ts...> : is_one_of<T, Ts...> {};
} // namespace detail
} // 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. *
******************************************************************************/
#pragma once
#include <cstdint>
#include <map>
#include <vector>
#include "caf/detail/is_one_of.hpp"
#include "caf/timespan.hpp"
// -- forward declarations (this header cannot include fwd.hpp) ----------------
namespace caf {
class config_value;
enum class atom_value : uint64_t;
} // namespace caf
// -- trait --------------------------------------------------------------------
namespace caf {
namespace detail {
/// Checks wheter `T` is in a primitive value type in `config_value`.
template <class T>
using is_primitive_config_value =
is_one_of<T, int64_t, bool, double, atom_value, timespan, std::string,
std::vector<config_value>, std::map<std::string, config_value>>;
} // namespace detail
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* *
* 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>
#include "caf/detail/type_traits.hpp"
namespace caf {
namespace detail {
/// Moves the value from `x` if it is not a pointer (e.g., `optional` or
/// `expected`), returns `*x` otherwise.
template <class T>
T& move_if_not_ptr(T* x) {
return *x;
}
/// Moves the value from `x` if it is not a pointer (e.g., `optional` or
/// `expected`), returns `*x` otherwise.
template <class T, class E = enable_if_t<!std::is_pointer<T>::value>>
T&& move_if_not_ptr(T& x) {
return std::move(*x);
}
} // namespace detail
} // 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. *
******************************************************************************/
#pragma once
#include "caf/detail/parser/ascii_to_int.hpp"
namespace caf {
namespace detail {
namespace parser {
// Sum up integers when parsing positive integers.
// @returns `false` on an overflow, otherwise `true`.
// @pre `isdigit(c) || (Base == 16 && isxdigit(c))`
template <int Base, class T>
bool add_ascii(T& x, char c) {
ascii_to_int<Base, T> f;
auto before = x;
x = (x * Base) + f(c);
return before <= x;
}
} // namespace parser
} // namespace detail
} // 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. *
******************************************************************************/
#pragma once
namespace caf {
namespace detail {
namespace parser {
template <int Base, class T>
struct ascii_to_int {
// @pre `c` is a valid ASCII digit, i.e., matches [0-9].
constexpr T operator()(char c) const {
return c - '0';
}
};
template <class T>
struct ascii_to_int<16, T> {
// @pre `c` is a valid ASCII hex digit, i.e., matches [0-9A-Fa-f].
constexpr T operator()(char c) const {
// Numbers start at position 48 in the ASCII table.
// Uppercase characters start at position 65 in the ASCII table.
// Lowercase characters start at position 97 in the ASCII table.
return c <= '9' ? c - '0' : (c <= 'F' ? 10 + (c - 'A') : 10 + (c - 'a'));
}
};
} // namespace parser
} // namespace detail
} // namespace caf
This diff is collapsed.
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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
namespace caf {
namespace detail {
namespace parser {
/// Returns whether `c` equals `C`.
template <char C>
bool is_char(char c) {
return c == C;
}
/// Returns whether `c` equals `C` (case insensitive).
template <char C>
bool is_ichar(char c) {
static_assert(C >= 'a' && C <= 'z', "Expected a-z (lowercase).");
return c == C || c == (C - 32);
}
} // namespace parser
} // namespace detail
} // 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. *
******************************************************************************/
#pragma once
namespace caf {
namespace detail {
namespace parser {
/// Returns whether `c` is a valid digit for a given base.
template <int Base>
bool is_digit(char c);
template <>
inline bool is_digit<2>(char c) {
return c == '0' || c == '1';
}
template <>
inline bool is_digit<8>(char c) {
return c >= '0' && c <= '7';
}
template <>
inline bool is_digit<10>(char c) {
return c >= '0' && c <= '9';
}
template <>
inline bool is_digit<16>(char c) {
return (c >= '0' && c <= '9')
|| (c >= 'A' && c <= 'F')
|| (c >= 'a' && c <= 'f');
}
} // namespace parser
} // namespace detail
} // 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. *
******************************************************************************/
#pragma once
#include <cstdint>
#include <ctype.h>
#include <string>
#include "caf/atom.hpp"
#include "caf/detail/parser/fsm.hpp"
#include "caf/detail/parser/is_char.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/pec.hpp"
namespace caf {
namespace detail {
namespace parser {
/// Reads a number, i.e., on success produces either an `int64_t` or a
/// `double`.
template <class Iterator, class Sentinel, class Consumer>
void read_atom(state<Iterator, Sentinel>& ps, Consumer& consumer) {
size_t pos = 0;
char buf[11];
memset(buf, 0, sizeof(buf));
auto is_legal = [](char c) {
return isalnum(c) || c == '_' || c == ' ';
};
auto append = [&](char c) {
if (pos == sizeof(buf) - 1)
return false;
buf[pos++] = c;
return true;
};
auto g = caf::detail::make_scope_guard([&] {
if (ps.code <= pec::trailing_character)
consumer.value(atom(buf));
});
start();
state(init) {
transition(init, " \t")
transition(read_chars, '\'')
}
state(read_chars) {
transition(done, '\'')
transition(read_chars, is_legal, append(ch), pec::too_many_characters)
}
term_state(done) {
transition(done, " \t")
}
fin();
}
} // namespace parser
} // namespace detail
} // 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. *
******************************************************************************/
#pragma once
#include <cstdint>
#include <string>
#include "caf/detail/parser/fsm.hpp"
#include "caf/detail/parser/is_char.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/pec.hpp"
namespace caf {
namespace detail {
namespace parser {
/// Reads a boolean.
template <class Iterator, class Sentinel, class Consumer>
void read_bool(state<Iterator, Sentinel>& ps, Consumer& consumer) {
bool res = false;
auto g = make_scope_guard([&] {
if (ps.code <= pec::trailing_character)
consumer.value(res);
});
start();
state(init) {
transition(has_f, 'f')
transition(has_t, 't')
}
state(has_f) {
transition(has_fa, 'a')
}
state(has_fa) {
transition(has_fal, 'l')
}
state(has_fal) {
transition(has_fals, 's')
}
state(has_fals) {
transition(done, 'e', res = false)
}
state(has_t) {
transition(has_tr, 'r')
}
state(has_tr) {
transition(has_tru, 'u')
}
state(has_tru) {
transition(done, 'e', res = true)
}
term_state(done) {
// nop
}
fin();
}
} // namespace parser
} // namespace detail
} // 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. *
******************************************************************************/
#pragma once
#include <ctype.h>
#include <stack>
#include "caf/detail/parser/fsm.hpp"
#include "caf/detail/parser/read_atom.hpp"
#include "caf/detail/parser/read_bool.hpp"
#include "caf/detail/parser/read_number_or_timespan.hpp"
#include "caf/detail/parser/read_string.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/pec.hpp"
namespace caf {
namespace detail {
namespace parser {
// Example input:
//
// [section1]
// value1 = 123
// value2 = "string"
// subsection1 = {
// value3 = 1.23
// value4 = 4e20
// }
// [section2]
// value5 = 'atom'
// value6 = [1, 'two', "three", {
// a = "b",
// b = "c",
// }]
//
template <class Iterator, class Sentinel, class Consumer>
void read_ini_comment(state<Iterator, Sentinel>& ps, Consumer&&) {
start();
term_state(init) {
transition(done, '\n')
transition(init)
}
term_state(done) {
// nop
}
fin();
}
template <class Iterator, class Sentinel, class Consumer>
void read_ini_value(state<Iterator, Sentinel>& ps, Consumer&& consumer);
template <class Iterator, class Sentinel, class Consumer>
void read_ini_list(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
start();
state(init) {
epsilon(before_value)
}
state(before_value) {
transition(before_value, " \t\n")
transition(done, ']', consumer.end_list())
fsm_epsilon(read_ini_comment(ps, consumer), before_value, ';')
fsm_epsilon(read_ini_value(ps, consumer), after_value)
}
state(after_value) {
transition(after_value, " \t\n")
transition(before_value, ',')
transition(done, ']', consumer.end_list())
fsm_epsilon(read_ini_comment(ps, consumer), after_value, ';')
}
term_state(done) {
// nop
}
fin();
}
template <class Iterator, class Sentinel, class Consumer>
void read_ini_map(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
std::string key;
auto alnum_or_dash = [](char x) {
return isalnum(x) || x == '-' || x == '_';
};
start();
state(init) {
epsilon(await_key_name)
}
state(await_key_name) {
transition(await_key_name, " \t\n")
fsm_epsilon(read_ini_comment(ps, consumer), await_key_name, ';')
transition(read_key_name, alphabetic_chars, key = ch)
transition(done, '}', consumer.end_map())
}
// Reads a key of a "key=value" line.
state(read_key_name) {
transition(read_key_name, alnum_or_dash, key += ch)
epsilon(await_assignment)
}
// Reads the assignment operator in a "key=value" line.
state(await_assignment) {
transition(await_assignment, " \t")
transition(await_value, '=', consumer.key(std::move(key)))
}
// Reads the value in a "key=value" line.
state(await_value) {
transition(await_value, " \t")
fsm_epsilon(read_ini_value(ps, consumer), after_value)
}
// Waits for end-of-line after reading a value
state(after_value) {
transition(after_value, " \t\n")
transition(await_key_name, ',')
transition(done, '}', consumer.end_map())
fsm_epsilon(read_ini_comment(ps, consumer), after_value, ';')
}
term_state(done) {
//nop
}
fin();
}
template <class Iterator, class Sentinel, class Consumer>
void read_ini_value(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
start();
state(init) {
fsm_epsilon(read_string(ps, consumer), done, '"')
fsm_epsilon(read_atom(ps, consumer), done, '\'')
fsm_epsilon(read_number(ps, consumer), done, '.')
fsm_epsilon(read_bool(ps, consumer), done, "ft")
fsm_epsilon(read_number_or_timespan(ps, consumer), done, "0123456789+-")
fsm_transition(read_ini_list(ps, consumer.begin_list()), done, '[')
fsm_transition(read_ini_map(ps, consumer.begin_map()), done, '{')
}
term_state(done) {
// nop
}
fin();
}
/// Reads an INI formatted input.
template <class Iterator, class Sentinel, class Consumer>
void read_ini_section(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
using std::swap;
std::string tmp;
auto alnum_or_dash = [](char x) {
return isalnum(x) || x == '-' || x == '_';
};
auto emit_key = [&] {
std::string key;
swap(tmp, key);
consumer.key(std::move(key));
};
auto g = make_scope_guard([&] {
if (ps.code <= pec::trailing_character)
consumer.end_map();
});
start();
// Dispatches to read sections, comments, or key/value pairs.
term_state(init) {
transition(init, " \t\n")
fsm_epsilon(read_ini_comment(ps, consumer), init, ';')
transition(read_key_name, alphanumeric_chars, tmp = ch)
}
// Reads a key of a "key=value" line.
state(read_key_name) {
transition(read_key_name, alnum_or_dash, tmp += ch)
epsilon(await_assignment)
}
// Reads the assignment operator in a "key=value" line.
state(await_assignment) {
transition(await_assignment, " \t")
transition(await_value, '=', emit_key())
}
// Reads the value in a "key=value" line.
state(await_value) {
transition(await_value, " \t")
fsm_epsilon(read_ini_value(ps, consumer), await_eol)
}
// Waits for end-of-line after reading a value
term_state(await_eol) {
transition(await_eol, " \t")
fsm_epsilon(read_ini_comment(ps, consumer), init, ';')
transition(init, '\n')
}
fin();
}
/// Reads an INI formatted input.
template <class Iterator, class Sentinel, class Consumer>
void read_ini(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
using std::swap;
std::string tmp;
auto alnum_or_dash = [](char x) {
return isalnum(x) || x == '-' || x == '_';
};
auto begin_section = [&]() -> decltype(consumer.begin_map()) {
std::string key;
swap(tmp, key);
consumer.key(std::move(key));
return consumer.begin_map();
};
start();
// Scanning for first section.
term_state(init) {
transition(init, " \t\n")
fsm_epsilon(read_ini_comment(ps, consumer), init, ';')
transition(start_section, '[')
}
// Read the section key after reading an '['.
state(start_section) {
transition(start_section, " \t")
transition(read_section_name, alphabetic_chars, tmp = ch)
}
// Reads a section name such as "[foo]".
state(read_section_name) {
transition(read_section_name, alnum_or_dash, tmp += ch)
epsilon(close_section)
}
// Wait for the closing ']', preceded by any number of whitespaces.
state(close_section) {
transition(close_section, " \t")
fsm_transition(read_ini_section(ps, begin_section()), init, ']')
}
fin();
}
} // namespace parser
} // namespace detail
} // 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. *
******************************************************************************/
#pragma once
#include <cstdint>
#include "caf/detail/parser/add_ascii.hpp"
#include "caf/detail/parser/fsm.hpp"
#include "caf/detail/parser/is_char.hpp"
#include "caf/detail/parser/is_digit.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/parser/sub_ascii.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/pec.hpp"
namespace caf {
namespace detail {
namespace parser {
/// Reads a number, i.e., on success produces either an `int64_t` or a
/// `double`.
template <class Iterator, class Sentinel, class Consumer>
void read_number(state<Iterator, Sentinel>& ps, Consumer& consumer) {
// Any exponent larger than 511 always overflows.
static constexpr int max_double_exponent = 511;
// We assume a simple integer until proven wrong.
enum result_type_t { integer, positive_double, negative_double };
auto result_type = integer;
// Adjusts our mantissa, e.g., 1.23 becomes 123 with a dec_exp of -2.
auto dec_exp = 0;
// Exponent part of a floating point literal.
auto exp = 0;
// Our result when reading a floating point number.
auto dbl_res = 0.;
// Our result when reading an integer number.
int64_t int_res = 0;
// Computes the result on success.
auto g = caf::detail::make_scope_guard([&] {
if (ps.code <= pec::trailing_character) {
if (result_type == integer) {
consumer.value(int_res);
return;
}
// Compute final floating point number.
// 1) Fix the exponent.
exp += dec_exp;
// 2) Check whether exponent is in valid range.
if (exp < -max_double_exponent) {
ps.code = pec::exponent_underflow;
return;
}
if (exp > max_double_exponent) {
ps.code = pec::exponent_overflow;
return;
}
// 3) Scale result.
// Pre-computed powers of 10 for the scaling loop.
static double powerTable[] = {1e1, 1e2, 1e4, 1e8, 1e16,
1e32, 1e64, 1e128, 1e256};
auto i = 0;
if (exp < 0) {
for (auto n = -exp; n != 0; n >>= 1, ++i)
if (n & 0x01)
dbl_res /= powerTable[i];
} else {
for (auto n = exp; n != 0; n >>= 1, ++i)
if (n & 0x01)
dbl_res *= powerTable[i];
}
// 4) Fix sign and call consumer.
consumer.value(result_type == positive_double ? dbl_res : -dbl_res);
}
});
// Switches from parsing an integer to parsing a double.
auto ch_res = [&](result_type_t x) {
CAF_ASSERT(result_type == integer);
result_type = x;
// We parse doubles as positive number and restore the sign in `g`.
dbl_res = result_type == negative_double
? -static_cast<double>(int_res)
: static_cast<double>(int_res);
};
// Reads the a decimal place.
auto rd_decimal = [&](char c) {
--dec_exp;
return add_ascii<10>(dbl_res, c);
};
// Definition of our parser FSM.
start();
state(init) {
transition(init, " \t")
transition(has_plus, '+')
transition(has_minus, '-')
transition(pos_zero, '0')
epsilon(has_plus)
}
// "+" or "-" alone aren't numbers.
state(has_plus) {
transition(leading_dot, '.', ch_res(positive_double))
transition(pos_zero, '0')
epsilon(pos_dec)
}
state(has_minus) {
transition(leading_dot, '.', ch_res(negative_double))
transition(neg_zero, '0')
epsilon(neg_dec)
}
// Disambiguate base.
term_state(pos_zero) {
transition(start_pos_bin, "bB")
transition(start_pos_hex, "xX")
transition(trailing_dot, '.', ch_res(positive_double))
epsilon(pos_oct)
}
term_state(neg_zero) {
transition(start_neg_bin, "bB")
transition(start_neg_hex, "xX")
transition(trailing_dot, '.', ch_res(negative_double))
epsilon(neg_oct)
}
// Binary integers.
state(start_pos_bin) {
epsilon(pos_bin)
}
term_state(pos_bin) {
transition(pos_bin, "01", add_ascii<2>(int_res, ch), pec::integer_overflow)
}
state(start_neg_bin) {
epsilon(neg_bin)
}
term_state(neg_bin) {
transition(neg_bin, "01", sub_ascii<2>(int_res, ch), pec::integer_underflow)
}
// Octal integers.
state(start_pos_oct) {
epsilon(pos_oct)
}
term_state(pos_oct) {
transition(pos_oct, octal_chars, add_ascii<8>(int_res, ch),
pec::integer_overflow)
}
state(start_neg_oct) {
epsilon(neg_oct)
}
term_state(neg_oct) {
transition(neg_oct, octal_chars, sub_ascii<8>(int_res, ch),
pec::integer_underflow)
}
// Hexal integers.
state(start_pos_hex) {
epsilon(pos_hex)
}
term_state(pos_hex) {
transition(pos_hex, hexadecimal_chars, add_ascii<16>(int_res, ch),
pec::integer_overflow)
}
state(start_neg_hex) {
epsilon(neg_hex)
}
term_state(neg_hex) {
transition(neg_hex, hexadecimal_chars, sub_ascii<16>(int_res, ch),
pec::integer_underflow)
}
// Reads the integer part of the mantissa or a positive decimal integer.
term_state(pos_dec) {
transition(pos_dec, decimal_chars, add_ascii<10>(int_res, ch),
pec::integer_overflow)
transition(has_e, "eE", ch_res(positive_double))
transition(trailing_dot, '.', ch_res(positive_double))
}
// Reads the integer part of the mantissa or a negative decimal integer.
term_state(neg_dec) {
transition(neg_dec, decimal_chars, sub_ascii<10>(int_res, ch),
pec::integer_underflow)
transition(has_e, "eE", ch_res(negative_double))
transition(trailing_dot, '.', ch_res(negative_double))
}
// ".", "+.", etc. aren't valid numbers, so this state isn't terminal.
state(leading_dot) {
transition(after_dot, decimal_chars, rd_decimal(ch), pec::exponent_underflow)
}
// "1." is a valid number, so a trailing dot is a terminal state.
term_state(trailing_dot) {
epsilon(after_dot)
}
// Read the decimal part of a mantissa.
term_state(after_dot) {
transition(after_dot, decimal_chars, rd_decimal(ch), pec::exponent_underflow)
transition(has_e, "eE")
}
// "...e", "...e+", and "...e-" aren't valid numbers, so these states are not
// terminal.
state(has_e) {
transition(has_plus_after_e, '+')
transition(has_minus_after_e, '-')
transition(pos_exp, decimal_chars, add_ascii<10>(exp, ch),
pec::exponent_overflow)
}
state(has_plus_after_e) {
transition(pos_exp, decimal_chars, add_ascii<10>(exp, ch),
pec::exponent_overflow)
}
state(has_minus_after_e) {
transition(neg_exp, decimal_chars, sub_ascii<10>(exp, ch),
pec::exponent_underflow)
}
// Read a positive exponent.
term_state(pos_exp) {
transition(pos_exp, decimal_chars, add_ascii<10>(exp, ch),
pec::exponent_overflow)
}
// Read a negative exponent.
term_state(neg_exp) {
transition(neg_exp, decimal_chars, sub_ascii<10>(exp, ch),
pec::exponent_underflow)
}
fin();
}
} // namespace parser
} // namespace detail
} // 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. *
******************************************************************************/
#pragma once
#include <chrono>
#include <cstdint>
#include <string>
#include "caf/detail/parser/fsm.hpp"
#include "caf/detail/parser/is_char.hpp"
#include "caf/detail/parser/read_number.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/none.hpp"
#include "caf/optional.hpp"
#include "caf/pec.hpp"
#include "caf/timestamp.hpp"
#include "caf/variant.hpp"
namespace caf {
namespace detail {
namespace parser {
/// Reads a number or a duration, i.e., on success produces an `int64_t`, a
/// `double`, or a `timespan`.
template <class Iterator, class Sentinel, class Consumer>
void read_number_or_timespan(state<Iterator, Sentinel>& ps,
Consumer& consumer) {
using namespace std::chrono;
struct interim_consumer {
variant<none_t, int64_t, double> interim;
void value(int64_t x) {
interim = x;
}
void value(double x) {
interim = x;
}
};
optional<timespan> res;
interim_consumer ic;
auto has_int = [&] { return holds_alternative<int64_t>(ic.interim); };
auto has_dbl = [&] { return holds_alternative<double>(ic.interim); };
auto get_int = [&] { return get<int64_t>(ic.interim); };
auto g = make_scope_guard([&] {
if (ps.code <= pec::trailing_character) {
if (res != none) {
consumer.value(*res);
} else if (!holds_alternative<none_t>(ic.interim)) {
if (has_int())
consumer.value(get_int());
else
consumer.value(get<double>(ic.interim));
}
}
});
start();
state(init) {
fsm_epsilon(read_number(ps, ic), has_number)
}
term_state(has_number) {
epsilon_if(has_int(), has_integer)
epsilon_if(has_dbl(), has_double)
}
term_state(has_double) {
error_transition(pec::fractional_timespan, "unms")
}
term_state(has_integer) {
transition(have_u, 'u')
transition(have_n, 'n')
transition(have_m, 'm')
transition(done, 's', res = seconds(get_int()))
}
state(have_u) {
transition(done, 's', res = microseconds(get_int()))
}
state(have_n) {
transition(done, 's', res = nanoseconds(get_int()))
}
state(have_m) {
transition(have_mi, 'i')
transition(done, 's', res = milliseconds(get_int()))
}
state(have_mi) {
transition(done, 'n', res = minutes(get_int()))
}
term_state(done) {
// nop
}
fin();
}
} // namespace parser
} // namespace detail
} // 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. *
******************************************************************************/
#pragma once
#include <cstdint>
#include <string>
#include "caf/detail/scope_guard.hpp"
#include "caf/detail/parser/fsm.hpp"
#include "caf/detail/parser/is_char.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/pec.hpp"
namespace caf {
namespace detail {
namespace parser {
/// Reads a number, i.e., on success produces either an `int64_t` or a
/// `double`.
template <class Iterator, class Sentinel, class Consumer>
void read_string(state<Iterator, Sentinel>& ps, Consumer& consumer) {
std::string res;
auto g = caf::detail::make_scope_guard([&] {
if (ps.code <= pec::trailing_character)
consumer.value(std::move(res));
});
start();
state(init) {
transition(init, " \t")
transition(read_chars, '"')
}
state(read_chars) {
transition(escape, '\\')
transition(done, '"')
error_transition(pec::unexpected_newline, '\n')
transition(read_chars, any_char, res += ch)
}
state(escape) {
transition(read_chars, 'n', res += '\n')
transition(read_chars, 'r', res += '\r')
transition(read_chars, 't', res += '\t')
transition(read_chars, '\\', res += '\\')
transition(read_chars, '"', res += '"')
error_transition(pec::illegal_escape_sequence)
}
term_state(done) {
transition(done, " \t")
}
fin();
}
} // namespace parser
} // namespace detail
} // namespace caf
...@@ -18,38 +18,45 @@ ...@@ -18,38 +18,45 @@
#pragma once #pragma once
#include <string> #include <cstdint>
#include <istream>
#include <functional>
#include "caf/atom.hpp" #include "caf/pec.hpp"
#include "caf/variant.hpp"
#include "caf/optional.hpp"
#include "caf/config_value.hpp"
namespace caf { namespace caf {
namespace detail { namespace detail {
namespace parser {
struct parse_ini_t {
/// Denotes an optional error output stream template <class Iterator, class Sentinel = Iterator>
using opt_err = optional<std::ostream&>; struct state {
/// Denotes a callback for consuming configuration values. Iterator i;
using config_consumer = std::function<void (size_t, std::string, Sentinel e;
config_value&, opt_err)>; pec code;
int32_t line = 1;
/// Parse the given input stream as INI formatted data and int32_t column = 1;
/// calls the consumer with every key-value pair.
/// @param input Input stream of INI formatted text. /// Returns the null terminator when reaching the end of the string,
/// @param consumer_fun Callback consuming generated key-value pairs. /// otherwise the next character.
/// @param errors Output stream for parser errors. char next() noexcept {
void operator()(std::istream& input, ++i;
const config_consumer& consumer_fun, if (i != e) {
opt_err errors = none) const; auto c = *i;
if (c == '\n') {
++line;
column = 1;
} else {
++column;
}
return c;
}
return '\0';
}
/// Returns the null terminator if `i == e`, otherwise the current character.
char current() const noexcept {
return i != e ? *i : '\0';
}
}; };
constexpr parse_ini_t parse_ini = parse_ini_t{}; } // namespace parser
} // namespace detail } // namespace detail
} // namespace caf } // 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. *
******************************************************************************/
#pragma once
#include "caf/detail/parser/ascii_to_int.hpp"
namespace caf {
namespace detail {
namespace parser {
// Subtracs integers when parsing negative integers.
// @returns `false` on an underflow, otherwise `true`.
// @pre `isdigit(c) || (Base == 16 && isxdigit(c))`
template <int Base, class T>
bool sub_ascii(T& x, char c) {
ascii_to_int<Base, T> f;
auto before = x;
x = (x * Base) - f(c);
return before >= x;
}
} // namespace parser
} // namespace detail
} // 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. *
******************************************************************************/
#pragma once
/// Concatenates x and y into a single token.
#define CAF_PP_CAT(x, y) x ## y
/// Evaluate x and y before concatenating into a single token.
#define CAF_PP_PASTE(x, y) CAF_PP_CAT(x, y)
/// Computes the number of arguments of a variadic pack.
#define CAF_PP_SIZE(...) \
CAF_PP_SIZE_I(__VA_ARGS__, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, \
52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, \
37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, \
22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, \
6, 5, 4, 3, 2, 1, )
#define CAF_PP_SIZE_I(e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, \
e13, e14, e15, e16, e17, e18, e19, e20, e21, e22, e23, \
e24, e25, e26, e27, e28, e29, e30, e31, e32, e33, e34, \
e35, e36, e37, e38, e39, e40, e41, e42, e43, e44, e45, \
e46, e47, e48, e49, e50, e51, e52, e53, e54, e55, e56, \
e57, e58, e59, e60, e61, e62, e63, size, ...) \
size
/// Allows overload-like macro functions.
#define CAF_PP_OVERLOAD(PREFIX, ...) \
CAF_PP_PASTE(PREFIX, CAF_PP_SIZE(__VA_ARGS__))
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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 <map>
#include <string>
#include <type_traits>
#include <vector>
#include "caf/fwd.hpp"
#include "caf/timestamp.hpp"
namespace caf {
namespace detail {
template <size_t Bytes>
struct type_name_builder_int_size;
template <>
struct type_name_builder_int_size<1> {
inline void operator()(std::string& result) const {
result += "8";
}
};
template <>
struct type_name_builder_int_size<2> {
inline void operator()(std::string& result) const {
result += "16";
}
};
template <>
struct type_name_builder_int_size<4> {
inline void operator()(std::string& result) const {
result += "32";
}
};
template <>
struct type_name_builder_int_size<8> {
inline void operator()(std::string& result) const {
result += "64";
}
};
template <class T, bool IsInteger = std::is_integral<T>::value>
struct type_name_builder;
template <>
struct type_name_builder<bool, true> {
inline void operator()(std::string& result) const {
result += "boolean";
}
};
template <>
struct type_name_builder<float, false> {
inline void operator()(std::string& result) const {
result += "32-bit real";
}
};
template <>
struct type_name_builder<double, false> {
inline void operator()(std::string& result) const {
result += "64-bit real";
}
};
template <>
struct type_name_builder<timespan, false> {
inline void operator()(std::string& result) const {
result += "timespan";
}
};
template <>
struct type_name_builder<std::string, false> {
inline void operator()(std::string& result) const {
result += "string";
}
};
template <>
struct type_name_builder<atom_value, false> {
inline void operator()(std::string& result) const {
result += "atom";
}
};
template <class T>
struct type_name_builder<T, true> {
void operator()(std::string& result) const {
// TODO: replace with if constexpr when switching to C++17
if (!std::is_signed<T>::value)
result += 'u';
result += "int";
type_name_builder_int_size<sizeof(T)> g;
g(result);
}
};
template <class T>
struct type_name_builder<std::vector<T>, false> {
void operator()(std::string& result) const {
result += "list of ";
type_name_builder<T> g;
g(result);
}
};
template <class T>
struct type_name_builder<std::map<std::string, T>, false> {
void operator()(std::string& result) const {
result += "dictionary of ";
type_name_builder<T> g;
g(result);
}
};
template <class T>
std::string type_name() {
std::string result;
type_name_builder<T> f;
f(result);
return result;
}
} // namespace detail
} // namespace caf
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/timestamp.hpp" #include "caf/timestamp.hpp"
#include "caf/detail/is_one_of.hpp"
#include "caf/detail/type_list.hpp" #include "caf/detail/type_list.hpp"
#define CAF_HAS_MEMBER_TRAIT(name) \ #define CAF_HAS_MEMBER_TRAIT(name) \
...@@ -125,19 +126,6 @@ struct disjunction<X, Xs...> { ...@@ -125,19 +126,6 @@ struct disjunction<X, Xs...> {
static constexpr bool value = X || disjunction<Xs...>::value; static constexpr bool value = X || disjunction<Xs...>::value;
}; };
/// Checks wheter `X` is in the template parameter pack Ts.
template <class X, class... Ts>
struct is_one_of;
template <class X>
struct is_one_of<X> : std::false_type {};
template <class X, class... Ts>
struct is_one_of<X, X, Ts...> : std::true_type {};
template <class X, typename T0, class... Ts>
struct is_one_of<X, T0, Ts...> : is_one_of<X, Ts...> {};
/// Checks whether `T` is a `std::chrono::duration`. /// Checks whether `T` is a `std::chrono::duration`.
template <class T> template <class T>
struct is_duration : std::false_type {}; struct is_duration : std::false_type {};
......
...@@ -19,9 +19,14 @@ ...@@ -19,9 +19,14 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include <map>
#include <memory> #include <memory>
#include <tuple> #include <tuple>
#include "caf/detail/is_one_of.hpp"
#include "caf/detail/is_primitive_config_value.hpp"
#include "caf/timespan.hpp"
namespace caf { namespace caf {
// -- 1 param templates -------------------------------------------------------- // -- 1 param templates --------------------------------------------------------
...@@ -67,52 +72,56 @@ template <class, class...> class output_stream; ...@@ -67,52 +72,56 @@ template <class, class...> class output_stream;
// -- classes ------------------------------------------------------------------ // -- classes ------------------------------------------------------------------
class abstract_actor;
class abstract_group;
class actor; class actor;
class error;
class group;
class message;
class node_id;
class behavior;
class duration;
class resumable;
class actor_addr; class actor_addr;
class actor_pool;
class message_id;
class serializer;
class actor_clock; class actor_clock;
class actor_proxy; class actor_companion;
class local_actor;
class ref_counted;
class actor_config; class actor_config;
class actor_control_block;
class actor_pool;
class actor_proxy;
class actor_registry;
class actor_system; class actor_system;
class actor_system_config;
class behavior;
class blocking_actor;
class config_option;
class config_option_adder;
class config_option_set;
class config_value;
class deserializer; class deserializer;
class downstream_manager;
class downstream_manager_base;
class duration;
class error;
class event_based_actor;
class execution_unit;
class forwarding_actor_proxy;
class group;
class group_module; class group_module;
class message_view;
class scoped_actor;
class inbound_path; class inbound_path;
class outbound_path; class local_actor;
class abstract_actor;
class abstract_group;
class actor_registry;
class blocking_actor;
class execution_unit;
class proxy_registry;
class stream_manager;
class actor_companion;
class mailbox_element; class mailbox_element;
class message;
class message_builder; class message_builder;
class message_handler; class message_handler;
class scheduled_actor; class message_id;
class message_view;
class node_id;
class outbound_path;
class proxy_registry;
class ref_counted;
class response_promise; class response_promise;
class event_based_actor; class resumable;
class scheduled_actor;
class scoped_actor;
class serializer;
class stream_manager;
class type_erased_tuple; class type_erased_tuple;
class type_erased_value; class type_erased_value;
class downstream_manager;
class actor_control_block;
class actor_system_config;
class uniform_type_info_map; class uniform_type_info_map;
class forwarding_actor_proxy;
class downstream_manager_base;
// -- structs ------------------------------------------------------------------ // -- structs ------------------------------------------------------------------
...@@ -130,6 +139,16 @@ struct invalid_actor_addr_t; ...@@ -130,6 +139,16 @@ struct invalid_actor_addr_t;
struct illegal_message_element; struct illegal_message_element;
struct prohibit_top_level_spawn_marker; struct prohibit_top_level_spawn_marker;
// -- free template functions --------------------------------------------------
template <class T>
config_option make_config_option(const char* category, const char* name,
const char* description);
template <class T>
config_option make_config_option(T& storage, const char* category,
const char* name, const char* description);
// -- enums -------------------------------------------------------------------- // -- enums --------------------------------------------------------------------
enum class stream_priority; enum class stream_priority;
...@@ -140,6 +159,12 @@ enum class atom_value : uint64_t; ...@@ -140,6 +159,12 @@ 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;
// -- functions ----------------------------------------------------------------
/// @relates actor_system_config
const std::map<std::string, std::map<std::string, config_value>>&
content(const actor_system_config&);
// -- intrusive containers ----------------------------------------------------- // -- intrusive containers -----------------------------------------------------
namespace intrusive { namespace intrusive {
......
...@@ -196,6 +196,11 @@ public: ...@@ -196,6 +196,11 @@ public:
return context_->system(); return context_->system();
} }
/// Returns the config of the hosting actor system.
inline const actor_system_config& config() const {
return system().config();
}
/// Returns the clock of the actor system. /// Returns the clock of the actor system.
inline actor_clock& clock() const { inline actor_clock& clock() const {
return home_system().clock(); return home_system().clock();
......
...@@ -155,8 +155,7 @@ public: ...@@ -155,8 +155,7 @@ public:
/// Represents a single format string field. /// Represents a single format string field.
struct field { struct field {
field_type kind; field_type kind;
const char* first; std::string text;
const char* last;
}; };
/// Stores a parsed format string as list of fields. /// Stores a parsed format string as list of fields.
...@@ -243,7 +242,7 @@ public: ...@@ -243,7 +242,7 @@ public:
/// Parses `format_str` into a format description vector. /// Parses `format_str` into a format description vector.
/// @warning The returned vector can have pointers into `format_str`. /// @warning The returned vector can have pointers into `format_str`.
static line_format parse_format(const char* format_str); static line_format parse_format(const std::string& format_str);
/// Skips path in `filename`. /// Skips path in `filename`.
static const char* skip_path(const char* filename); static const char* skip_path(const char* filename);
...@@ -271,6 +270,18 @@ public: ...@@ -271,6 +270,18 @@ public:
return "[]"; return "[]";
} }
// -- individual flags -------------------------------------------------------
static constexpr int inline_output_flag = 0x01;
static constexpr int uncolored_console_flag = 0x02;
static constexpr int colored_console_flag = 0x04;
// -- composed flags ---------------------------------------------------------
static constexpr int console_output_flag = 0x06;
private: private:
void handle_event(event& x); void handle_event(event& x);
...@@ -288,9 +299,17 @@ private: ...@@ -288,9 +299,17 @@ private:
void stop(); void stop();
inline bool has(int flag) const noexcept {
return (flags_ & flag) != 0;
}
inline void set(int flag) noexcept {
flags_ |= flag;
}
actor_system& system_; actor_system& system_;
int level_; int level_;
bool inline_output_; int flags_;
detail::shared_spinlock aids_lock_; detail::shared_spinlock aids_lock_;
std::unordered_map<std::thread::id, actor_id> aids_; std::unordered_map<std::thread::id, actor_id> aids_;
std::thread thread_; std::thread thread_;
...@@ -302,6 +321,7 @@ private: ...@@ -302,6 +321,7 @@ private:
line_format file_format_; line_format file_format_;
line_format console_format_; line_format console_format_;
std::fstream file_; std::fstream file_;
std::string component_filter;
}; };
std::string to_string(logger::field_type x); std::string to_string(logger::field_type x);
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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 <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"
#include "caf/pec.hpp"
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) {
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) {
return {category, name, description, &detail::option_meta_state<T>::instance,
std::addressof(storage)};
}
// -- backward compatbility, do not use for new code ! -------------------------
// Inverts the value when writing to `storage`.
config_option make_negated_config_option(bool& storage, const char* category,
const char* name,
const char* description);
// 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);
// Reads timespans, but stores an integer representing millisecond resolution.
config_option make_ms_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);
CAF_SPECIALIZE_MAKE_CONFIG_OPTION(size_t);
CAF_SPECIALIZE_MAKE_CONFIG_OPTION(std::string);
} // namespace caf
...@@ -339,6 +339,9 @@ struct message::cli_arg { ...@@ -339,6 +339,9 @@ struct message::cli_arg {
/// Creates a CLI argument storing its matched argument in `dest`. /// Creates a CLI argument storing its matched argument in `dest`.
cli_arg(std::string nstr, std::string tstr, atom_value& arg); cli_arg(std::string nstr, std::string tstr, atom_value& arg);
/// Creates a CLI argument storing its matched argument in `dest`.
cli_arg(std::string nstr, std::string tstr, timespan& arg);
/// Creates a CLI argument storing its matched argument in `dest`. /// Creates a CLI argument storing its matched argument in `dest`.
cli_arg(std::string nstr, std::string tstr, std::string& arg); cli_arg(std::string nstr, std::string tstr, std::string& arg);
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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 <cstdint>
#include "caf/fwd.hpp"
namespace caf {
/// PEC stands for "Parser Error Code". This enum contains error codes used by
/// various CAF parsers.
enum class pec : uint8_t {
/// Not-an-error.
success = 0,
/// Parser succeeded but found trailing character(s).
trailing_character = 1,
/// Parser stopped after reaching the end while still expecting input.
unexpected_eof,
/// Parser stopped after reading an unexpected character.
unexpected_character,
/// Parsed integer exceeds the number of available bits of a `timespan`.
timespan_overflow,
/// Tried constructing a `timespan` with from a floating point number.
fractional_timespan = 5,
/// Too many characters for an atom.
too_many_characters,
/// Unrecognized character after escaping `\`.
illegal_escape_sequence,
/// Misplaced newline, e.g., inside a string.
unexpected_newline,
/// Parsed positive integer exceeds the number of available bits.
integer_overflow,
/// Parsed negative integer exceeds the number of available bits.
integer_underflow = 10,
/// Exponent of parsed double is less than the minimum supported exponent.
exponent_underflow,
/// Exponent of parsed double is greater than the maximum supported exponent.
exponent_overflow,
/// Parsed type does not match the expected type.
type_mismatch,
/// Stopped at an unrecognized option name.
not_an_option,
/// Stopped at an unparseable argument.
illegal_argument = 15,
/// Stopped because an argument was omitted.
missing_argument,
/// Stopped because the key of a category was taken.
illegal_category,
};
error make_error(pec code);
error make_error(pec code, size_t line, size_t column);
const char* to_string(pec x);
} // namespace caf
...@@ -18,20 +18,20 @@ ...@@ -18,20 +18,20 @@
#pragma once #pragma once
#include <deque> #include <array>
#include <chrono> #include <chrono>
#include <thread> #include <condition_variable>
#include <random>
#include <cstddef> #include <cstddef>
#include <deque>
#include <mutex> #include <mutex>
#include <condition_variable> #include <random>
#include <thread>
#include "caf/resumable.hpp"
#include "caf/actor_system_config.hpp" #include "caf/actor_system_config.hpp"
#include "caf/policy/unprofiled.hpp"
#include "caf/detail/double_ended_queue.hpp" #include "caf/detail/double_ended_queue.hpp"
#include "caf/policy/unprofiled.hpp"
#include "caf/resumable.hpp"
#include "caf/timespan.hpp"
namespace caf { namespace caf {
namespace policy { namespace policy {
...@@ -45,17 +45,15 @@ public: ...@@ -45,17 +45,15 @@ public:
// A thread-safe queue implementation. // A thread-safe queue implementation.
using queue_type = detail::double_ended_queue<resumable>; using queue_type = detail::double_ended_queue<resumable>;
using usec = std::chrono::microseconds;
// configuration for aggressive/moderate/relaxed poll strategies. // configuration for aggressive/moderate/relaxed poll strategies.
struct poll_strategy { struct poll_strategy {
size_t attempts; size_t attempts;
size_t step_size; size_t step_size;
size_t steal_interval; size_t steal_interval;
usec sleep_duration; timespan sleep_duration;
}; };
// what is needed to implement the waiting strategy. // what is needed to implement the waiting strategy.
struct wait_strategy { struct wait_strategy {
std::mutex lock; std::mutex lock;
std::condition_variable cv; std::condition_variable cv;
...@@ -74,23 +72,8 @@ public: ...@@ -74,23 +72,8 @@ public:
// Holds job job queue of a worker and a random number generator. // Holds job job queue of a worker and a random number generator.
struct worker_data { struct worker_data {
inline explicit worker_data(scheduler::abstract_coordinator* p) explicit worker_data(scheduler::abstract_coordinator* p);
: rengine(std::random_device{}()), worker_data(const worker_data& other);
// no need to worry about wrap-around; if `p->num_workers() < 2`,
// `uniform` will not be used anyway
uniform(0, p->num_workers() - 2),
strategies{
{p->system().config().work_stealing_aggressive_poll_attempts, 1,
p->system().config().work_stealing_aggressive_steal_interval,
usec{0}},
{p->system().config().work_stealing_moderate_poll_attempts, 1,
p->system().config().work_stealing_moderate_steal_interval,
usec{p->system().config().work_stealing_moderate_sleep_duration_us}},
{1, 0, p->system().config().work_stealing_relaxed_steal_interval,
usec{p->system().config().work_stealing_relaxed_sleep_duration_us}}
} {
// nop
}
// This queue is exposed to other workers that may attempt to steal jobs // This queue is exposed to other workers that may attempt to steal jobs
// from it and the central scheduling unit can push new jobs to the queue. // from it and the central scheduling unit can push new jobs to the queue.
...@@ -98,7 +81,7 @@ public: ...@@ -98,7 +81,7 @@ public:
// needed to generate pseudo random numbers // needed to generate pseudo random numbers
std::default_random_engine rengine; std::default_random_engine rengine;
std::uniform_int_distribution<size_t> uniform; std::uniform_int_distribution<size_t> uniform;
poll_strategy strategies[3]; std::array<poll_strategy, 3> strategies;
wait_strategy waitdata; wait_strategy waitdata;
}; };
...@@ -130,10 +113,10 @@ public: ...@@ -130,10 +113,10 @@ public:
auto& lock = d(self).waitdata.lock; auto& lock = d(self).waitdata.lock;
auto& cv = d(self).waitdata.cv; auto& cv = d(self).waitdata.cv;
{ // guard scope { // guard scope
std::unique_lock<std::mutex> guard(lock); std::unique_lock<std::mutex> guard(lock);
// check if the worker is sleeping // check if the worker is sleeping
if (d(self).waitdata.sleeping && !d(self).queue.empty() ) if (d(self).waitdata.sleeping && !d(self).queue.empty() )
cv.notify_one(); cv.notify_one();
} }
} }
...@@ -182,10 +165,10 @@ public: ...@@ -182,10 +165,10 @@ public:
bool notimeout = true; bool notimeout = true;
size_t i=1; size_t i=1;
do { do {
{ // guard scope { // guard scope
std::unique_lock<std::mutex> guard(lock); std::unique_lock<std::mutex> guard(lock);
sleeping = true; sleeping = true;
if (!cv.wait_for(guard, relaxed.sleep_duration, if (!cv.wait_for(guard, relaxed.sleep_duration,
[&] { return !d(self).queue.empty(); })) [&] { return !d(self).queue.empty(); }))
notimeout = false; notimeout = false;
sleeping = false; sleeping = false;
...@@ -195,7 +178,7 @@ public: ...@@ -195,7 +178,7 @@ public:
} else { } else {
notimeout = true; notimeout = true;
if ((i % relaxed.steal_interval) == 0) if ((i % relaxed.steal_interval) == 0)
job = try_steal(self); job = try_steal(self);
} }
++i; ++i;
} while(job == nullptr); } while(job == nullptr);
......
...@@ -94,10 +94,16 @@ public: ...@@ -94,10 +94,16 @@ public:
/// Deletes all proxies. /// Deletes all proxies.
void clear(); void clear();
/// Returns the hosting actor system.
inline actor_system& system() { inline actor_system& system() {
return system_; return system_;
} }
/// Returns the hosting actor system.
inline const actor_system& system() const {
return system_;
}
inline size_t size() const { inline size_t size() const {
return proxies_.size(); return proxies_.size();
} }
......
...@@ -65,6 +65,8 @@ public: ...@@ -65,6 +65,8 @@ public:
return system_; return system_;
} }
const actor_system_config& config() const;
inline size_t max_throughput() const { inline size_t max_throughput() const {
return max_throughput_; return max_throughput_;
} }
......
...@@ -61,19 +61,23 @@ public: ...@@ -61,19 +61,23 @@ public:
protected: protected:
void start() override { void start() override {
// initialize workers vector // Create initial state for all workers.
typename worker_type::policy_data init{this};
// Prepare workers vector.
auto num = num_workers(); auto num = num_workers();
workers_.reserve(num); workers_.reserve(num);
// Create worker instanes.
for (size_t i = 0; i < num; ++i) for (size_t i = 0; i < num; ++i)
workers_.emplace_back(new worker_type(i, this, max_throughput_)); workers_.emplace_back(new worker_type(i, this, init, max_throughput_));
// start all workers now that all workers have been initialized // Start all workers.
for (auto& w : workers_) for (auto& w : workers_)
w->start(); w->start();
// launch thread for dispatching timeouts and delayed messages // Launch an additional background thread for dispatching timeouts and
// delayed messages.
timer_ = std::thread{[&] { timer_ = std::thread{[&] {
clock_.run_dispatch_loop(); clock_.run_dispatch_loop();
}}; }};
// run remaining startup code // Run remaining startup code.
super::start(); super::start();
} }
......
...@@ -38,13 +38,11 @@ ...@@ -38,13 +38,11 @@
#include <unordered_map> #include <unordered_map>
#include "caf/actor_system_config.hpp" #include "caf/actor_system_config.hpp"
#include "caf/defaults.hpp"
#include "caf/scheduler/coordinator.hpp" #include "caf/logger.hpp"
#include "caf/policy/profiled.hpp" #include "caf/policy/profiled.hpp"
#include "caf/policy/work_stealing.hpp" #include "caf/policy/work_stealing.hpp"
#include "caf/scheduler/coordinator.hpp"
#include "caf/logger.hpp"
namespace caf { namespace caf {
namespace scheduler { namespace scheduler {
...@@ -178,14 +176,19 @@ public: ...@@ -178,14 +176,19 @@ public:
} }
void init(actor_system_config& cfg) override { void init(actor_system_config& cfg) override {
namespace sr = defaults::scheduler;
super::init(cfg); super::init(cfg);
file_.open(cfg.scheduler_profiling_output_file); auto fname = get_or(cfg, "scheduler.profiling-output-file",
sr::profiling_output_file);
file_.open(fname);
if (!file_) if (!file_)
std::cerr << R"([WARNING] could not open file ")" std::cerr << R"([WARNING] could not open file ")"
<< cfg.scheduler_profiling_output_file << fname
<< R"(" (no profiler output will be generated))" << R"(" (no profiler output will be generated))"
<< std::endl; << std::endl;
resolution_ = msec{cfg.scheduler_profiling_ms_resolution}; auto res = get_or(cfg, "scheduler.profiling-resolution",
sr::profiling_resolution);
resolution_ = std::chrono::duration_cast<msec>(res);
} }
void start() override { void start() override {
......
...@@ -40,12 +40,13 @@ public: ...@@ -40,12 +40,13 @@ public:
using coordinator_ptr = coordinator<Policy>*; using coordinator_ptr = coordinator<Policy>*;
using policy_data = typename Policy::worker_data; using policy_data = typename Policy::worker_data;
worker(size_t worker_id, coordinator_ptr worker_parent, size_t throughput) worker(size_t worker_id, coordinator_ptr worker_parent,
const policy_data& init, size_t throughput)
: execution_unit(&worker_parent->system()), : execution_unit(&worker_parent->system()),
max_throughput_(throughput), max_throughput_(throughput),
id_(worker_id), id_(worker_id),
parent_(worker_parent), parent_(worker_parent),
data_(worker_parent) { data_(init) {
// nop // nop
} }
......
...@@ -27,8 +27,8 @@ ...@@ -27,8 +27,8 @@
namespace caf { namespace caf {
/// SEC stands for "System Error Code". This enum contains /// SEC stands for "System Error Code". This enum contains error codes for
/// error codes used internally by CAF. /// ::actor_system and its modules.
enum class sec : uint8_t { enum class sec : uint8_t {
/// No error. /// No error.
none = 0, none = 0,
......
...@@ -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 {
...@@ -47,59 +48,57 @@ constexpr bool SumTypes() { ...@@ -47,59 +48,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<MutableSumType<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<MutableSumType<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`.
...@@ -108,9 +107,7 @@ template <class T, class U> ...@@ -108,9 +107,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>
...@@ -175,5 +172,4 @@ visit(Visitor&& f, T&& x, Ts&&... xs) { ...@@ -175,5 +172,4 @@ visit(Visitor&& f, T&& x, Ts&&... xs) {
std::forward<Ts>(xs)...); std::forward<Ts>(xs)...);
} }
} // namespace caf } // 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. *
******************************************************************************/
#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. *
******************************************************************************/
#pragma once
#include <chrono>
#include <cstdint>
namespace caf {
/// A portable timespan type with nanosecond resolution.
using timespan = std::chrono::duration<int64_t, std::nano>;
} // namespace caf
...@@ -22,10 +22,9 @@ ...@@ -22,10 +22,9 @@
#include <string> #include <string>
#include <cstdint> #include <cstdint>
namespace caf { #include "caf/timespan.hpp"
/// A portable timespan type with nanosecond resolution. namespace caf {
using timespan = std::chrono::duration<int64_t, std::nano>;
/// A portable timestamp with nanosecond resolution anchored at the UNIX epoch. /// A portable timestamp with nanosecond resolution anchored at the UNIX epoch.
using timestamp = std::chrono::time_point<std::chrono::system_clock, timespan>; using timestamp = std::chrono::time_point<std::chrono::system_clock, timespan>;
......
...@@ -27,22 +27,20 @@ ...@@ -27,22 +27,20 @@
#include <unordered_map> #include <unordered_map>
#include <condition_variable> #include <condition_variable>
#include "caf/send.hpp" #include "caf/actor_ostream.hpp"
#include "caf/actor_system.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/after.hpp" #include "caf/after.hpp"
#include "caf/others.hpp" #include "caf/defaults.hpp"
#include "caf/duration.hpp" #include "caf/duration.hpp"
#include "caf/actor_system.hpp" #include "caf/logger.hpp"
#include "caf/scoped_actor.hpp" #include "caf/others.hpp"
#include "caf/actor_ostream.hpp" #include "caf/policy/work_stealing.hpp"
#include "caf/system_messages.hpp"
#include "caf/scheduled_actor.hpp" #include "caf/scheduled_actor.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/scheduler/coordinator.hpp" #include "caf/scheduler/coordinator.hpp"
#include "caf/scoped_actor.hpp"
#include "caf/policy/work_stealing.hpp" #include "caf/send.hpp"
#include "caf/system_messages.hpp"
#include "caf/logger.hpp"
namespace caf { namespace caf {
namespace scheduler { namespace scheduler {
...@@ -235,6 +233,10 @@ public: ...@@ -235,6 +233,10 @@ public:
* implementation of coordinator * * implementation of coordinator *
******************************************************************************/ ******************************************************************************/
const actor_system_config& abstract_coordinator::config() const {
return system_.config();
}
bool abstract_coordinator::detaches_utility_actors() const { bool abstract_coordinator::detaches_utility_actors() const {
return true; return true;
} }
...@@ -247,8 +249,9 @@ void abstract_coordinator::start() { ...@@ -247,8 +249,9 @@ void abstract_coordinator::start() {
} }
void abstract_coordinator::init(actor_system_config& cfg) { void abstract_coordinator::init(actor_system_config& cfg) {
max_throughput_ = cfg.scheduler_max_throughput; namespace sr = defaults::scheduler;
num_workers_ = cfg.scheduler_max_threads; max_throughput_ = get_or(cfg, "scheduler.max-throughput", sr::max_throughput);
num_workers_ = get_or(cfg, "scheduler.max-threads", sr::max_threads);
} }
actor_system::module::id_t abstract_coordinator::id() const { actor_system::module::id_t abstract_coordinator::id() const {
......
...@@ -239,16 +239,18 @@ actor_system::actor_system(actor_system_config& cfg) ...@@ -239,16 +239,18 @@ actor_system::actor_system(actor_system_config& cfg)
profiled_sharing = 0x0102 profiled_sharing = 0x0102
}; };
sched_conf sc = stealing; sched_conf sc = stealing;
if (cfg.scheduler_policy == atom("sharing")) namespace sr = defaults::scheduler;
auto sr_policy = get_or(cfg, "scheduler.policy", sr::policy);
if (sr_policy == atom("sharing"))
sc = sharing; sc = sharing;
else if (cfg.scheduler_policy == atom("testing")) else if (sr_policy == atom("testing"))
sc = testing; sc = testing;
else if (cfg.scheduler_policy != atom("stealing")) else if (sr_policy != atom("stealing"))
std::cerr << "[WARNING] " << deep_to_string(cfg.scheduler_policy) std::cerr << "[WARNING] " << deep_to_string(sr_policy)
<< " is an unrecognized scheduler pollicy, " << " is an unrecognized scheduler pollicy, "
"falling back to 'stealing' (i.e. work-stealing)" "falling back to 'stealing' (i.e. work-stealing)"
<< std::endl; << std::endl;
if (cfg.scheduler_enable_profiling) if (get_or(cfg, "scheduler.enable-profiling", false))
sc = static_cast<sched_conf>(sc | profiled); sc = static_cast<sched_conf>(sc | profiled);
switch (sc) { switch (sc) {
default: // any invalid configuration falls back to work stealing default: // any invalid configuration falls back to work stealing
......
This diff is collapsed.
...@@ -18,67 +18,78 @@ ...@@ -18,67 +18,78 @@
#include "caf/config_option.hpp" #include "caf/config_option.hpp"
#include <cstring>
#include <iostream> #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;
namespace {
string get_long_name(const char* name) {
auto i= strchr(name, ',');
return i != nullptr ? string{name, i} : string{name};
}
string get_short_names(const char* name) {
auto substr = strchr(name, ',');
if (substr != nullptr)
return ++substr;
return string{};
}
} // namespace <anonymous>
namespace caf { namespace caf {
const char* type_name_visitor_tbl[] { config_option::config_option(string category, const char* name,
"a boolean", string description, const meta_state* meta,
"a float", void* value)
"a double", : category_(move(category)),
"a string", long_name_(get_long_name(name)),
"an atom_value", short_names_(get_short_names(name)),
"an 8-bit integer", description_(move(description)),
"an 8-bit unsigned integer", meta_(meta),
"a 16-bit integer", value_(value) {
"a 16-bit unsigned integer", CAF_ASSERT(meta_ != nullptr);
"a 32-bit integer", }
"a 32-bit unsigned integer",
"a 64-bit integer", string config_option::full_name() const {
"a 64-bit unsigned integer" std::string result = category();
}; result += '.';
result += long_name_;
config_option::config_option(const char* cat, const char* nm, const char* expl) return result;
: category_(cat), }
name_(nm),
explanation_(expl), error config_option::check(const config_value& x) const {
short_name_('\0') { CAF_ASSERT(meta_->check != nullptr);
auto last = name_.end(); return meta_->check(x);
auto comma = std::find(name_.begin(), last, ','); }
if (comma != last) {
auto i = comma; void config_option::store(const config_value& x) const {
++i; if (value_ != nullptr) {
if (i != last) CAF_ASSERT(meta_->store != nullptr);
short_name_ = *i; meta_->store(value_, x);
name_.erase(comma, last);
} }
} }
config_option::~config_option() { const std::string& config_option::type_name() const noexcept {
// nop return meta_->type_name;
} }
std::string config_option::full_name() const { bool config_option::is_flag() const noexcept {
std::string res = category(); return type_name() == "boolean";
res += '.';
auto name_begin = name();
const char* name_end = strchr(name(), ',');
if (name_end != nullptr)
res.insert(res.end(), name_begin, name_end);
else
res += name();
return res;
} }
void config_option::report_type_error(size_t ln, config_value& x, optional<config_value> config_option::get() const {
const char* expected, if (value_ != nullptr && meta_->get != nullptr)
optional<std::ostream&> out) { return meta_->get(value_);
if (!out) return none;
return;
type_name_visitor tnv;
*out << "error in line " << ln << ": expected "
<< expected << " found "
<< visit(tnv, x) << '\n';
} }
} // namespace caf } // 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_option_adder.hpp"
#include "caf/config_option_set.hpp"
namespace caf {
config_option_adder::config_option_adder(config_option_set& target,
const char* category)
: xs_(target),
category_(category) {
// nop
}
config_option_adder& config_option_adder::add_neg(bool& ref, const char* name,
const char* description) {
return add_impl(make_negated_config_option(ref, category_,
name, description));
}
config_option_adder& config_option_adder::add_us(size_t& ref, const char* name,
const char* description) {
return add_impl(make_us_resolution_config_option(ref, category_,
name, description));
}
config_option_adder& config_option_adder::add_ms(size_t& ref, const char* name,
const char* description) {
return add_impl(make_ms_resolution_config_option(ref, category_,
name, description));
}
config_option_adder& config_option_adder::add_impl(config_option&& opt) {
xs_.add(std::move(opt));
return *this;
}
} // 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_option_set.hpp"
#include <map>
#include <set>
#include "caf/config_option.hpp"
#include "caf/config_value.hpp"
#include "caf/detail/algorithms.hpp"
#include "caf/expected.hpp"
using std::string;
namespace {
struct string_builder {
std::string result;
};
template <size_t N>
string_builder& operator<<(string_builder& builder, const char (&cstr)[N]) {
builder.result.append(cstr, N - 1);
return builder;
}
string_builder& operator<<(string_builder& builder, char c) {
builder.result += c;
return builder;
}
string_builder& operator<<(string_builder& builder, const std::string& str) {
builder.result += str;
return builder;
}
void insert(string_builder& builder, size_t count, char ch) {
builder.result.insert(builder.result.end(), count, ch);
}
} // namespace <anonymous>
namespace caf {
config_option_set::config_option_set() {
// nop
}
config_option_set& config_option_set::add(config_option&& opt) {
opts_.emplace_back(std::move(opt));
return *this;
}
std::string config_option_set::help_text(bool global_only) const {
//<--- argument --------> <---- desciption ---->
// (-w|--write) <string> : output file
auto build_argument = [](const config_option& x) {
string_builder sb;
if (x.short_names().empty()) {
sb << " --";
if (x.category() != "global")
sb << x.category() << '.';
sb << x.long_name();
if (!x.is_flag())
sb << '=';
} else {
sb << " (";
for (auto c : x.short_names())
sb << '-' << c << '|';
sb << "--";
if (x.category() != "global")
sb << x.category() << '.';
sb << x.long_name() << ") ";
}
if (!x.is_flag())
sb << "<" << x.type_name() << '>';
return std::move(sb.result);
};
// Sort argument + description by category.
using pair = std::pair<std::string, option_pointer>;
std::set<std::string> categories;
std::multimap<std::string, pair> args;
size_t max_arg_size = 0;
for (auto& opt : opts_) {
if (!global_only || opt.category() == "global") {
auto arg = build_argument(opt);
max_arg_size = std::max(max_arg_size, arg.size());
categories.emplace(opt.category());
args.emplace(opt.category(), std::make_pair(std::move(arg), &opt));
}
}
// Build help text by iterating over all categories in the multimap.
string_builder builder;
for (auto& category : categories) {
auto rng = args.equal_range(category);
builder << category << " options:\n";
for (auto i = rng.first; i != rng.second; ++i) {
builder << i->second.first;
CAF_ASSERT(max_arg_size >= i->second.first.size());
insert(builder, max_arg_size - i->second.first.size(), ' ');
builder << " : " << i->second.second->description() << '\n';
}
builder << '\n';
}
return std::move(builder.result);
}
auto config_option_set::parse(config_map& config, argument_iterator first,
argument_iterator last) const
-> std::pair<pec, argument_iterator> {
// Sanity check.
if (first == last)
return {pec::success, last};
// Parses an argument.
using iter = string::const_iterator;
auto consume = [&](const config_option& opt, iter arg_begin, iter arg_end) {
// Extract option name and category.
auto opt_name = opt.long_name();
string opt_ctg = opt.category();
// Try inserting a new submap into the config or fill existing one.
auto& submap = config[opt_ctg];
// Flags only consume the current element.
if (opt.is_flag()) {
if (arg_begin != arg_end)
return pec::illegal_argument;
config_value cfg_true{true};
opt.store(cfg_true);
submap[opt_name] = cfg_true;
} else {
if (arg_begin == arg_end)
return pec::missing_argument;
auto val = config_value::parse(arg_begin, arg_end);
if (!val)
return pec::illegal_argument;
if (opt.check(*val) != none)
return pec::type_mismatch;
opt.store(*val);
submap[opt_name] = std::move(*val);
}
return pec::success;
};
// We loop over the first N-1 values, because we always consider two
// arguments at once.
for (auto i = first; i != last;) {
if (i->size() < 2)
return {pec::not_an_option, i};
if (*i== "--")
return {pec::success, std::next(first)};
if (i->compare(0, 2, "--") == 0) {
// Long options use the syntax "--<name>=<value>" and consume only a
// single argument.
static constexpr auto npos = std::string::npos;
auto assign_op = i->find('=');
auto name = assign_op == npos ? i->substr(2)
: i->substr(2, assign_op - 2);
auto opt = cli_long_name_lookup(name);
if (opt == nullptr)
return {pec::not_an_option, i};
auto code = consume(*opt,
assign_op == npos ? i->end()
: i->begin() + assign_op + 1,
i->end());
if (code != pec::success)
return {code, i};
++i;
} else if (i->front() == '-') {
// Short options have three possibilities.
auto opt = cli_short_name_lookup((*i)[1]);
if (opt == nullptr)
return {pec::not_an_option, i};
if (opt->is_flag()) {
// 1) "-f" for flags, consumes one argument
auto code = consume(*opt, i->begin() + 2, i->end());
if (code != pec::success)
return {code, i};
++i;
} else {
if (i->size() == 2) {
// 2) "-k <value>", consumes both arguments
auto j = std::next(i);
if (j == last) {
return {pec::missing_argument, j};
}
auto code = consume(*opt, j->begin(), j->end());
if (code != pec::success)
return {code, i};
std::advance(i, 2);
} else {
// 3) "-k<value>" (no space), consumes one argument
auto code = consume(*opt, i->begin() + 2, i->end());
if (code != pec::success)
return {code, i};
++i;
}
}
} else {
// No leading '-' found on current position.
return {pec::not_an_option, i};
}
}
return {pec::success, last};
}
config_option_set::parse_result
config_option_set::parse(config_map& config,
const std::vector<string>& args) const {
return parse(config, args.begin(), args.end());
}
config_option_set::option_pointer
config_option_set::cli_long_name_lookup(const string& name) const {
// We accept "caf#" prefixes for backward compatibility, but ignore them.
size_t offset = name.compare(0, 4, "caf#") != 0 ? 0u : 4u;
// Extract category and long name.
string category;
string long_name;
auto sep = name.find('.', offset);
if (sep == string::npos) {
category = "global";
if (offset == 0)
long_name = name;
else
long_name = name.substr(offset);
} else {
category = name.substr(offset, sep);
long_name = name.substr(sep + 1);
}
// Scan all options for a match.
return detail::ptr_find_if(opts_, [&](const config_option& opt) {
return opt.category() == category && opt.long_name() == long_name;
});
}
config_option_set::option_pointer
config_option_set::cli_short_name_lookup(char short_name) const {
return detail::ptr_find_if(opts_, [&](const config_option& opt) {
return opt.short_names().find(short_name) != string::npos;
});
}
config_option_set::option_pointer
config_option_set::qualified_name_lookup(const std::string& category,
const std::string& long_name) const {
return detail::ptr_find_if(opts_, [&](const config_option& opt) {
return opt.category() == category && opt.long_name() == long_name;
});
}
config_option_set::option_pointer
config_option_set::qualified_name_lookup(const std::string& name) const {
auto sep = name.find('.');
if (sep == string::npos)
return nullptr;
return qualified_name_lookup(name.substr(0, sep), name.substr(sep + 1));
}
} // namespace caf
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -55,7 +55,7 @@ void await_all_locals_down(actor_system& sys, std::initializer_list<actor> xs) { ...@@ -55,7 +55,7 @@ void await_all_locals_down(actor_system& sys, std::initializer_list<actor> xs) {
ys.push_back(x); ys.push_back(x);
} }
// Don't block when using the test coordinator. // Don't block when using the test coordinator.
if (sys.config().scheduler_policy != atom("testing")) if (atom("testing") != get_or(sys.config(), "scheduler.policy", atom("")))
self->wait_for(ys); self->wait_for(ys);
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -118,7 +118,7 @@ behavior tester(event_based_actor* self, const actor& aut) { ...@@ -118,7 +118,7 @@ behavior tester(event_based_actor* self, const actor& aut) {
struct config : actor_system_config { struct config : actor_system_config {
config() { config() {
scheduler_policy = atom("testing"); set("scheduler.policy", atom("testing"));
} }
}; };
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -265,7 +265,7 @@ behavior ping_multiplexed3(ping_actor* self, bool* had_timeout, ...@@ -265,7 +265,7 @@ behavior ping_multiplexed3(ping_actor* self, bool* had_timeout,
struct config : actor_system_config { struct config : actor_system_config {
config() { config() {
scheduler_policy = atom("testing"); set("scheduler.policy", atom("testing"));
} }
}; };
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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