Commit b82f6a80 authored by Dominik Charousset's avatar Dominik Charousset

Use id_block namespace instead of _type_ids suffix

parent 7b598dff
......@@ -324,15 +324,9 @@ behavior curl_master(stateful_actor<master_state>* self) {
// signal handling for ctrl+c
std::atomic<bool> shutdown_flag{false};
struct config : actor_system_config {
config() {
init_global_meta_objects<curl_fuse_type_ids>();
}
};
} // namespace
void caf_main(actor_system& system, const config&) {
void caf_main(actor_system& system) {
// install signal handler
struct sigaction act;
act.sa_handler = [](int) { shutdown_flag = true; };
......@@ -368,4 +362,4 @@ void caf_main(actor_system& system, const config&) {
curl_global_cleanup();
}
CAF_MAIN(io::middleman)
CAF_MAIN(id_block::curl_fuse, io::middleman)
......@@ -3,11 +3,11 @@
// Manual refs: 24-27, 30-34, 75-78, 81-84 (ConfiguringActorApplications)
// 23-33 (TypeInspection)
#include <string>
#include <vector>
#include <cassert>
#include <utility>
#include <iostream>
#include <string>
#include <utility>
#include <vector>
#include "caf/all.hpp"
......@@ -24,8 +24,8 @@ CAF_BEGIN_TYPE_ID_BLOCK(custom_types_1, first_custom_type_id)
CAF_END_TYPE_ID_BLOCK(custom_types_1)
// --(rst-type-id-block-end)--
using std::cout;
using std::cerr;
using std::cout;
using std::endl;
using std::vector;
......@@ -69,7 +69,7 @@ void testee(event_based_actor* self, size_t remaining) {
else
self->quit();
};
self->become (
self->become(
// note: we sent a foo_pair2, but match on foo_pair
// that works because both are aliases for std::pair<int, int>
[=](const foo_pair& val) {
......@@ -79,20 +79,10 @@ void testee(event_based_actor* self, size_t remaining) {
[=](const foo& val) {
aout(self) << to_string(val) << endl;
set_next_behavior();
}
);
});
}
// --(rst-config-begin)--
class config : public actor_system_config {
public:
config() {
init_global_meta_objects<custom_types_1_type_ids>();
}
};
// --(rst-config-end)--
void caf_main(actor_system& system, const config&) {
void caf_main(actor_system& sys) {
// two variables for testing serialization
foo2 f1;
foo2 f2;
......@@ -103,30 +93,28 @@ void caf_main(actor_system& system, const config&) {
// I/O buffer
binary_serializer::container_type buf;
// write f1 to buffer
binary_serializer bs{system, buf};
binary_serializer bs{sys, buf};
auto e = bs(f1);
if (e) {
std::cerr << "*** unable to serialize foo2: "
<< system.render(e) << std::endl;
std::cerr << "*** unable to serialize foo2: " << sys.render(e) << std::endl;
return;
}
// read f2 back from buffer
binary_deserializer bd{system, buf};
binary_deserializer bd{sys, buf};
e = bd(f2);
if (e) {
std::cerr << "*** unable to serialize foo2: "
<< system.render(e) << std::endl;
std::cerr << "*** unable to serialize foo2: " << sys.render(e) << std::endl;
return;
}
// must be equal
assert(to_string(f1) == to_string(f2));
// spawn a testee that receives two messages of user-defined type
auto t = system.spawn(testee, 2u);
scoped_actor self{system};
auto t = sys.spawn(testee, 2u);
scoped_actor self{sys};
// send t a foo
self->send(t, foo{std::vector<int>{1, 2, 3, 4}, 5});
// send t a foo_pair2
self->send(t, foo_pair2{3, 4});
}
CAF_MAIN()
CAF_MAIN(id_block::custom_types_1)
......@@ -64,15 +64,8 @@ behavior testee(event_based_actor* self) {
};
}
class config : public actor_system_config {
public:
config() {
init_global_meta_objects<custom_types_2_type_ids>();
}
};
void caf_main(actor_system& system, const config&) {
anon_send(system.spawn(testee), foo{1, 2});
void caf_main(actor_system& sys) {
anon_send(sys.spawn(testee), foo{1, 2});
}
CAF_MAIN()
CAF_MAIN(id_block::custom_types_2)
......@@ -105,15 +105,8 @@ behavior testee(event_based_actor* self) {
};
}
class config : public actor_system_config {
public:
config() {
init_global_meta_objects<custom_types_3_type_ids>();
}
};
void caf_main(actor_system& system, const config&) {
void caf_main(actor_system& system) {
anon_send(system.spawn(testee), foo{1, 2});
}
CAF_MAIN()
CAF_MAIN(id_block::custom_types_3)
......@@ -175,15 +175,9 @@ private:
behavior eating_; // wait for some time, then go thinking again
};
struct config : actor_system_config {
config() {
init_global_meta_objects<dining_philosophers_type_ids>();
}
};
} // namespace
void caf_main(actor_system& system, const config&) {
void caf_main(actor_system& system) {
scoped_actor self{system};
// create five chopsticks
aout(self) << "chopstick ids are:";
......@@ -200,4 +194,4 @@ void caf_main(actor_system& system, const config&) {
self->spawn<philosopher>(names[i], chopsticks[i], chopsticks[(i + 1) % 5]);
}
CAF_MAIN()
CAF_MAIN(id_block::dining_philosophers)
......@@ -128,13 +128,7 @@ std::ostream& operator<<(std::ostream& out, const expected<int>& x) {
return out << to_string(x.error());
}
struct config : actor_system_config {
config() {
init_global_meta_objects<fan_out_request_type_ids>();
}
};
void caf_main(actor_system& sys, const config&) {
void caf_main(actor_system& sys) {
// Spawn our matrix.
static constexpr int rows = 3;
static constexpr int columns = 6;
......@@ -164,4 +158,4 @@ void caf_main(actor_system& sys, const config&) {
<< '\n';
}
CAF_MAIN()
CAF_MAIN(id_block::fan_out_request)
......@@ -73,12 +73,6 @@ private:
behavior empty_;
};
struct config : actor_system_config {
config() {
init_global_meta_objects<fixed_stack_type_ids>();
}
};
void caf_main(actor_system& system) {
scoped_actor self{system};
auto st = self->spawn<fixed_stack>(5u);
......@@ -97,4 +91,4 @@ void caf_main(actor_system& system) {
self->send_exit(st, exit_reason::user_shutdown);
}
CAF_MAIN()
CAF_MAIN(id_block::fixed_stack)
......@@ -73,7 +73,6 @@ public:
bool server_mode = false;
config() {
init_global_meta_objects<group_chat_type_ids>();
opt_group{custom_options_, "global"}
.add(name, "name,n", "set name")
.add(group_uris, "group,g", "join group")
......@@ -162,4 +161,4 @@ void caf_main(actor_system& system, const config& cfg) {
f(system, cfg);
}
CAF_MAIN(io::middleman)
CAF_MAIN(id_block::group_chat, io::middleman)
......@@ -102,7 +102,6 @@ void client_repl(function_view<calculator> f) {
struct config : actor_system_config {
config() {
add_actor_type("calculator", calculator_fun);
init_global_meta_objects<remote_spawn_type_ids>();
opt_group{custom_options_, "global"}
.add(port, "port,p", "set port")
.add(host, "host,H", "set node (ignored in server mode)")
......@@ -153,4 +152,4 @@ void caf_main(actor_system& system, const config& cfg) {
f(system, cfg);
}
CAF_MAIN(io::middleman)
CAF_MAIN(id_block::remote_spawn, io::middleman)
......@@ -126,7 +126,6 @@ behavior int_sink(event_based_actor* self) {
struct config : actor_system_config {
config() {
init_global_meta_objects<integer_stream_type_ids>();
opt_group{custom_options_, "global"}
.add(with_stage, "with-stage,s", "use a stage for filtering odd numbers")
.add(n, "num-values,n", "number of values produced by the source");
......@@ -148,4 +147,4 @@ void caf_main(actor_system& sys, const config& cfg) {
} // namespace
CAF_MAIN()
CAF_MAIN(id_block::integer_stream)
......@@ -22,6 +22,7 @@
#include "caf/actor_system_config.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/init_global_meta_objects.hpp"
namespace caf {
......@@ -33,8 +34,8 @@ struct exec_main_helper<detail::type_list<actor_system&>> {
using config = actor_system_config;
template <class F>
void operator()(F& fun, actor_system& sys, config&) {
fun(sys);
auto operator()(F& fun, actor_system& sys, const config&) {
return fun(sys);
}
};
......@@ -43,11 +44,30 @@ struct exec_main_helper<detail::type_list<actor_system&, const T&>> {
using config = T;
template <class F>
void operator()(F& fun, actor_system& sys, config& cfg) {
fun(sys, cfg);
auto operator()(F& fun, actor_system& sys, const config& cfg) {
return fun(sys, cfg);
}
};
template <class T>
void exec_main_init_meta_objects_single() {
if constexpr (std::is_base_of<actor_system::module, T>::value)
T::init_global_meta_objects();
else
init_global_meta_objects<T>();
}
template <class... Ts>
void exec_main_init_meta_objects() {
(exec_main_init_meta_objects_single<Ts>(), ...);
}
template <class T>
void exec_main_load_module(actor_system_config& cfg) {
if constexpr (std::is_base_of<actor_system::module, T>::value)
cfg.template load<T>();
}
template <class... Ts, class F = void (*)(actor_system&)>
int exec_main(F fun, int argc, char** argv,
const char* config_file_name = "caf-application.ini") {
......@@ -80,8 +100,7 @@ int exec_main(F fun, int argc, char** argv,
if (cfg.cli_helptext_printed)
return EXIT_SUCCESS;
// Load modules.
std::initializer_list<unit_t> unused{unit_t{cfg.template load<Ts>()}...};
CAF_IGNORE_UNUSED(unused);
(exec_main_load_module<Ts>(cfg), ...);
// Initialize the actor system.
actor_system system{cfg};
if (cfg.slave_mode) {
......@@ -92,13 +111,20 @@ int exec_main(F fun, int argc, char** argv,
return cfg.slave_mode_fun(system, cfg);
}
helper f;
f(fun, system, cfg);
return EXIT_SUCCESS;
using result_type = decltype(f(fun, system, cfg));
if constexpr (std::is_convertible<result_type, int>::value) {
return f(fun, system, cfg);
} else {
f(fun, system, cfg);
return EXIT_SUCCESS;
}
}
} // namespace caf
#define CAF_MAIN(...) \
int main(int argc, char** argv) { \
return ::caf::exec_main<__VA_ARGS__>(caf_main, argc, argv); \
caf::exec_main_init_meta_objects<__VA_ARGS__>(); \
caf::core::init_global_meta_objects(); \
return caf::exec_main<__VA_ARGS__>(caf_main, argc, argv); \
}
......@@ -52,8 +52,6 @@ template <class Range>
using make_type_id_sequence = typename type_id_sequence_helper<
type_id_pair<Range::begin, Range::end>>::type;
CAF_CORE_EXPORT void init_core_module_meta_objects();
} // namespace caf::detail
namespace caf {
......@@ -72,13 +70,17 @@ void init_global_meta_objects_impl(std::integer_sequence<uint16_t, Is...>) {
/// Initializes the global meta object table with all types in `ProjectIds`.
/// @warning calling this after constructing any ::actor_system is unsafe and
/// causes undefined behavior.
template <class ProjectIds = void>
template <class ProjectIds>
void init_global_meta_objects() {
detail::init_core_module_meta_objects();
if constexpr (!std::is_same<ProjectIds, void>::value) {
detail::make_type_id_sequence<ProjectIds> seq;
init_global_meta_objects_impl<ProjectIds>(seq);
}
detail::make_type_id_sequence<ProjectIds> seq;
init_global_meta_objects_impl<ProjectIds>(seq);
}
} // namespace caf
namespace caf::core {
/// Initializes the meta objects of the core module.
CAF_CORE_EXPORT void init_global_meta_objects();
} // namespace caf::core
......@@ -86,14 +86,17 @@ constexpr type_id_t first_custom_type_id = 200;
} // namespace caf
/// Starts a code block for registering custom types to CAF. Stores the first ID
/// for the project as `caf::${project_name}_first_type_id`. Usually, users
/// should use `caf::first_custom_type_id` as `first_id`. However, this
/// mechanism also enables modules to append IDs to a block of another module or
/// module. If two modules are developed separately to avoid dependencies, they
/// only need to define sufficiently large offsets to guarantee collision-free
/// IDs (CAF supports gaps in the ID space).
/// for the project as `caf::id_block::${project_name}_first_type_id`. Usually,
/// users should use `caf::first_custom_type_id` as `first_id`. However, this
/// mechanism also enables projects to append IDs to a block of another project.
/// If two projects are developed separately to avoid dependencies, they only
/// need to define sufficiently large offsets to guarantee collision-free IDs.
/// CAF supports gaps in the ID space.
///
/// @note CAF reserves all names with the suffix `_module`. For example, core
/// module uses the project name `core_module`.
#define CAF_BEGIN_TYPE_ID_BLOCK(project_name, first_id) \
namespace caf { \
namespace caf::id_block { \
constexpr type_id_t project_name##_type_id_counter_init = __COUNTER__; \
constexpr type_id_t project_name##_first_type_id = first_id; \
}
......@@ -105,9 +108,9 @@ constexpr type_id_t first_custom_type_id = 200;
template <> \
struct type_id<CAF_PP_EXPAND fully_qualified_name> { \
static constexpr type_id_t value \
= project_name##_first_type_id \
= id_block::project_name##_first_type_id \
+ (CAF_PP_CAT(CAF_PP_COUNTER, ()) \
- project_name##_type_id_counter_init - 1); \
- id_block::project_name##_type_id_counter_init - 1); \
}; \
template <> \
struct type_by_id<type_id<CAF_PP_EXPAND fully_qualified_name>::value> { \
......@@ -128,8 +131,8 @@ constexpr type_id_t first_custom_type_id = 200;
template <> \
struct type_id<CAF_PP_EXPAND fully_qualified_name> { \
static constexpr type_id_t value \
= project_name##_first_type_id \
+ (__COUNTER__ - project_name##_type_id_counter_init - 1); \
= id_block::project_name##_first_type_id \
+ (__COUNTER__ - id_block::project_name##_type_id_counter_init - 1); \
}; \
template <> \
struct type_by_id<type_id<CAF_PP_EXPAND fully_qualified_name>::value> { \
......@@ -190,14 +193,16 @@ constexpr type_id_t first_custom_type_id = 200;
CAF_PP_OVERLOAD(CAF_ADD_ATOM_, __VA_ARGS__)(__VA_ARGS__)
#endif
/// Finalizes a code block for registering custom types to CAF. Stores the last
/// type ID used by the project as `caf::${project_name}_last_type_id`.
/// Finalizes a code block for registering custom types to CAF. Defines a struct
/// `caf::type_id::${project_name}` with two static members `begin` and `end`.
/// The former stores the first assigned type ID. The latter stores the last
/// assigned type ID + 1.
#define CAF_END_TYPE_ID_BLOCK(project_name) \
namespace caf { \
namespace caf::id_block { \
constexpr type_id_t project_name##_last_type_id \
= project_name##_first_type_id \
+ (__COUNTER__ - project_name##_type_id_counter_init - 2); \
struct project_name##_type_ids { \
struct project_name { \
static constexpr type_id_t begin = project_name##_first_type_id; \
static constexpr type_id_t end = project_name##_last_type_id + 1; \
}; \
......@@ -308,7 +313,7 @@ CAF_END_TYPE_ID_BLOCK(core_module)
namespace caf::detail {
static constexpr type_id_t io_module_begin = core_module_type_ids::end;
static constexpr type_id_t io_module_begin = id_block::core_module::end;
static constexpr type_id_t io_module_end = io_module_begin + 19;
......
......@@ -233,8 +233,8 @@ actor_system::actor_system(actor_system_config& cfg)
}
// Make sure meta objects are loaded.
auto gmos = detail::global_meta_objects();
if (gmos.size() < core_module_type_ids::end
|| gmos[core_module_type_ids::begin].type_name == nullptr) {
if (gmos.size() < id_block::core_module::end
|| gmos[id_block::core_module::begin].type_name == nullptr) {
CAF_CRITICAL("actor_system created without calling "
"caf::init_global_meta_objects<>() before");
}
......
......@@ -36,11 +36,10 @@
#include "caf/upstream_msg.hpp"
#include "caf/uri.hpp"
namespace caf::detail {
namespace caf::core {
void init_core_module_meta_objects() {
make_type_id_sequence<core_module_type_ids> seq;
init_global_meta_objects_impl<core_module_type_ids>(seq);
void init_global_meta_objects() {
caf::init_global_meta_objects<id_block::core_module>();
}
} // namespace caf::detail
} // namespace caf::core
......@@ -5,6 +5,8 @@
#include "core-test.hpp"
int main(int argc, char** argv) {
caf::init_global_meta_objects<caf::core_test_type_ids>();
return caf::test::main(argc, argv);
using namespace caf;
init_global_meta_objects<id_block::core_test>();
core::init_global_meta_objects();
return test::main(argc, argv);
}
......@@ -80,13 +80,13 @@ CAF_TEST(meta objects allow serialization of objects) {
CAF_TEST(init_global_meta_objects takes care of creating a meta object table) {
auto xs = global_meta_objects();
CAF_REQUIRE_EQUAL(xs.size(), caf::core_test_last_type_id + 1u);
CAF_REQUIRE_EQUAL(xs.size(), caf::id_block::core_test::end);
CAF_CHECK_EQUAL(type_name_by_id_v<type_id_v<i32_wrapper>>, "i32_wrapper"s);
CAF_CHECK_EQUAL(type_name_by_id_v<type_id_v<i64_wrapper>>, "i64_wrapper"s);
CAF_CHECK_EQUAL(xs[type_id_v<i32_wrapper>].type_name, "i32_wrapper"s);
CAF_CHECK_EQUAL(xs[type_id_v<i64_wrapper>].type_name, "i64_wrapper"s);
CAF_MESSAGE("calling init_global_meta_objects again is a no-op");
init_global_meta_objects<core_test_type_ids>();
init_global_meta_objects<id_block::core_test>();
auto ys = global_meta_objects();
auto same = [](const auto& x, const auto& y) {
return x.type_name == y.type_name;
......
......@@ -118,4 +118,4 @@ CAF_END_TYPE_ID_BLOCK(io_module)
CAF_ALLOW_UNSAFE_MESSAGE_TYPE(caf::io::doorman_ptr)
CAF_ALLOW_UNSAFE_MESSAGE_TYPE(caf::io::scribe_ptr)
static_assert(caf::io_module_type_ids::end == caf::detail::io_module_end);
static_assert(caf::id_block::io_module::end == caf::detail::io_module_end);
......@@ -83,7 +83,7 @@ private:
} // namespace
void middleman::init_global_meta_objects() {
caf::init_global_meta_objects<io_module_type_ids>();
caf::init_global_meta_objects<id_block::io_module>();
}
actor_system::module* middleman::make(actor_system& sys, detail::type_list<>) {
......
......@@ -5,7 +5,9 @@
#include "io-test.hpp"
int main(int argc, char** argv) {
caf::init_global_meta_objects<caf::io_test_type_ids>();
caf::io::middleman::init_global_meta_objects();
return caf::test::main(argc, argv);
using namespace caf;
init_global_meta_objects<id_block::io_test>();
io::middleman::init_global_meta_objects();
core::init_global_meta_objects();
return test::main(argc, argv);
}
......@@ -7,7 +7,9 @@
#include "caf/io/middleman.hpp"
int main(int argc, char** argv) {
caf::init_global_meta_objects<caf::openssl_test_type_ids>();
caf::io::middleman::init_global_meta_objects();
return caf::test::main(argc, argv);
using namespace caf;
init_global_meta_objects<id_block::openssl_test>();
io::middleman::init_global_meta_objects();
core::init_global_meta_objects();
return test::main(argc, argv);
}
......@@ -30,49 +30,66 @@ The compiler expands this example code to the following.
return exec_main<io::middleman>(caf_main, argc, argv);
}
The function ``exec_main`` creates a config object, loads all modules
requested in ``CAF_MAIN`` and then calls ``caf_main``. A
minimal implementation for ``main`` performing all these steps manually
is shown in the next example for the sake of completeness.
The function ``exec_main`` performs several steps:
.. code-block:: C++
#. Initialize all meta objects for the type ID blocks listed in ``CAF_MAIN``.
#. Create a config object. If ``caf_main`` has two arguments, then CAF
assumes that the second argument is the configuration and the type gets
derived from that argument. Otherwise, CAF uses ``actor_system_config``.
#. Parse command line arguments and configuration file.
#. Load all modules requested in ``CAF_MAIN``.
#. Create an actor system.
#. Call ``caf_main`` with the actor system and optionally with ``config``.
int main(int argc, char** argv) {
actor_system_config cfg;
// read CLI options
cfg.parse(argc, argv);
// return immediately if a help text was printed
if (cfg.cli_helptext_printed)
return 0;
// load modules
cfg.load<io::middleman>();
// create actor system and call caf_main
actor_system system{cfg};
caf_main(system);
}
When implementing the steps performed by ``CAF_MAIN`` by hand, the ``main``
function would resemble the following (pseudo) code:
.. code-block:: C++
However, setting up config objects by hand is usually not necessary. CAF
automatically selects user-defined subclasses of
``actor_system_config`` if ``caf_main`` takes a second
parameter by reference, as shown in the minimal example below.
int main(int argc, char** argv) {
// Initialze the global type information before anything else.
init_global_meta_objects<...>();
core::init_global_meta_objects();
// Create the config.
actor_system_config cfg;
// Read CLI options.
cfg.parse(argc, argv);
// Return immediately if a help text was printed.
if (cfg.cli_helptext_printed)
return 0;
// Load modules.
cfg.load<...>();
// Create the actor system.
actor_system sys{cfg};
// Run user-defined code.
caf_main(sys, cfg);
}
Using ``CAF_MAIN`` simply automates that boilerplate code. A minimal example
with a custom type ID block as well as a custom configuration class with the I/O
module loaded looks as follows:
.. code-block:: C++
class my_config : public actor_system_config {
public:
my_config() {
// ...
}
};
CAF_BEGIN_TYPE_ID_BLOCK(my, first_custom_type_id)
// ...
CAF_END_TYPE_ID_BLOCK(my)
void caf_main(actor_system& system, const my_config& cfg) {
// ...
}
CAF_MAIN()
class my_config : public actor_system_config {
public:
my_config() {
// ...
}
};
Users can perform additional initialization, add custom program options, etc.
simply by implementing a default constructor.
void caf_main(actor_system& system, const my_config& cfg) {
// ...
}
CAF_MAIN(id_block::my, io::middleman)
.. _system-config-module:
......@@ -215,12 +232,9 @@ By assigning type IDs and providing ``inspect`` overloads, we provide static and
compile-time information for all our types. However, CAF also needs some
information at run-time for deserializing received data. The function
``init_global_meta_objects`` takes care fo registering all the state we need at
run-time.
.. literalinclude:: /examples/custom_type/custom_types_1.cpp
:language: C++
:start-after: --(rst-config-begin)--
:end-before: --(rst-config-end)--
run-time. This function usually gets called by ``CAF_MAIN`` automatically. When
not using this macro, users **must** call ``init_global_meta_objects`` before
any other CAF function.
Adding Custom Error Types
-------------------------
......
......@@ -749,7 +749,6 @@ struct config : public actor_system_config {
bool include_hidden_actors = false;
size_t verbosity = 0;
config() {
init_global_meta_objects<caf_vec_type_ids>();
opt_group{custom_options_, "global"}
.add(output_file, "output-file,o", "Path for the output file")
.add(include_hidden_actors, "include-hidden-actors,i",
......@@ -881,5 +880,4 @@ void caf_main(actor_system& sys, const config& cfg) {
} // namespace
CAF_MAIN()
CAF_MAIN(id_block::caf_vec)
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