Commit 71c043cc authored by Dominik Charousset's avatar Dominik Charousset

Migrate to the new messaging API

parent 77569942
...@@ -403,50 +403,29 @@ if(NOT APPLE AND NOT WIN32) ...@@ -403,50 +403,29 @@ if(NOT APPLE AND NOT WIN32)
endif() endif()
# -fPIC generates warnings on MinGW and Cygwin plus extra setup steps needed on MinGW # -fPIC generates warnings on MinGW and Cygwin plus extra setup steps needed on MinGW
if(MINGW) if(MINGW)
add_definitions(-D_WIN32_WINNT=0x0600) add_definitions(-D_WIN32_WINNT=0x0600 -DWIN32)
add_definitions(-DWIN32)
list(APPEND CAF_EXTRA_LDFLAGS -lws2_32 -liphlpapi -lpsapi) list(APPEND CAF_EXTRA_LDFLAGS -lws2_32 -liphlpapi -lpsapi)
# build static to avoid runtime dependencies to GCC libraries # build static to avoid runtime dependencies to GCC libraries
build_string("EXTRA_FLAGS" "-static") add_compile_options(-static)
elseif(CYGWIN) elseif(CYGWIN)
build_string("EXTRA_FLAGS" "-U__STRICT_ANSI__") add_compile_options(-U__STRICT_ANSI__)
endif() endif()
if (WIN32) if (WIN32)
list(APPEND CAF_EXTRA_LDFLAGS ws2_32 iphlpapi) list(APPEND CAF_EXTRA_LDFLAGS ws2_32 iphlpapi)
endif() endif()
# iOS support # iOS support
if(CAF_OSX_SYSROOT) if(CAF_OSX_SYSROOT)
set(CMAKE_OSX_SYSROOT "${CAF_OSX_SYSROOT}") set(CMAKE_OSX_SYSROOT "${CAF_OSX_SYSROOT}")
endif() endif()
if(CAF_IOS_DEPLOYMENT_TARGET) if(CAF_IOS_DEPLOYMENT_TARGET)
if(CAF_OSX_SYSROOT STREQUAL "iphonesimulator") if(CAF_OSX_SYSROOT STREQUAL "iphonesimulator")
build_string("EXTRA_FLAGS" add_compile_options("-mios-simulator-version-min=${CAF_IOS_DEPLOYMENT_TARGET}")
"-mios-simulator-version-min=${CAF_IOS_DEPLOYMENT_TARGET}")
else() else()
build_string("EXTRA_FLAGS" add_compile_options("-miphoneos-version-min=${CAF_IOS_DEPLOYMENT_TARGET}")
"-miphoneos-version-min=${CAF_IOS_DEPLOYMENT_TARGET}")
endif() endif()
endif() endif()
# check if the user provided CXXFLAGS, set defaults otherwise
if(NOT CMAKE_CXX_FLAGS)
set(CMAKE_CXX_FLAGS "-Wextra -Wall -pedantic ${EXTRA_FLAGS}")
endif()
if(NOT CMAKE_CXX_FLAGS_DEBUG)
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
endif()
if(NOT CMAKE_CXX_FLAGS_MINSIZEREL)
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os")
endif()
if(NOT CMAKE_CXX_FLAGS_RELEASE)
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
endif()
if(NOT CMAKE_CXX_FLAGS_RELWITHDEBINFO)
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -fno-omit-frame-pointer")
endif()
# set build default build type to RelWithDebInfo if not set
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE RelWithDebInfo)
endif()
# needed by subprojects # needed by subprojects
if (DEFINED CMAKE_LD_LIBS) if (DEFINED CMAKE_LD_LIBS)
list(APPEND ${CMAKE_LD_LIBS}) list(APPEND ${CMAKE_LD_LIBS})
...@@ -616,17 +595,6 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/CAFConfig.cmake" ...@@ -616,17 +595,6 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/CAFConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/CAFConfigVersion.cmake" "${CMAKE_CURRENT_BINARY_DIR}/CAFConfigVersion.cmake"
DESTINATION "${INSTALL_CAF_CMAKEDIR}") DESTINATION "${INSTALL_CAF_CMAKEDIR}")
# -- Fetch branch name and SHA if available ------------------------------------
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/release.txt")
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/release.txt" CAF_RELEASE)
string(REGEX REPLACE "\n" "" CAF_RELEASE "${CAF_RELEASE}")
else()
set(CAF_RELEASE "${CAF_VERSION}")
endif()
message(STATUS "Set release version for all documentation to ${CAF_RELEASE}.")
# -- Setup for building manual and API documentation --------------------------- # -- Setup for building manual and API documentation ---------------------------
if(NOT WIN32) if(NOT WIN32)
...@@ -661,11 +629,7 @@ invertYesNo(CAF_NO_EXCEPTIONS CAF_BUILD_WITH_EXCEPTIONS) ...@@ -661,11 +629,7 @@ invertYesNo(CAF_NO_EXCEPTIONS CAF_BUILD_WITH_EXCEPTIONS)
invertYesNo(CAF_NO_MEM_MANAGEMENT CAF_BUILD_MEM_MANAGEMENT) invertYesNo(CAF_NO_MEM_MANAGEMENT CAF_BUILD_MEM_MANAGEMENT)
invertYesNo(CAF_NO_OPENSSL CAF_BUILD_OPENSSL) invertYesNo(CAF_NO_OPENSSL CAF_BUILD_OPENSSL)
invertYesNo(CAF_NO_PYTHON CAF_BUILD_PYTHON) invertYesNo(CAF_NO_PYTHON CAF_BUILD_PYTHON)
# collect all compiler flags get_property(all_cxx_flags DIRECTORY PROPERTY COMPILE_OPTIONS)
string(TOUPPER "${CMAKE_BUILD_TYPE}" UPPER_BUILD_TYPE)
set(ALL_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${UPPER_BUILD_TYPE}}")
set(ALL_LD_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${CAF_EXTRA_LDFLAGS}")
string(STRIP "${ALL_LD_FLAGS}" ALL_LD_FLAGS)
# done # done
if(NOT CAF_NO_SUMMARY) if(NOT CAF_NO_SUMMARY)
message(STATUS message(STATUS
...@@ -689,7 +653,7 @@ if(NOT CAF_NO_SUMMARY) ...@@ -689,7 +653,7 @@ if(NOT CAF_NO_SUMMARY)
"\nBuild Python: ${CAF_BUILD_PYTHON}" "\nBuild Python: ${CAF_BUILD_PYTHON}"
"\n" "\n"
"\nCXX: ${CMAKE_CXX_COMPILER}" "\nCXX: ${CMAKE_CXX_COMPILER}"
"\nCXXFLAGS: ${ALL_CXX_FLAGS}" "\nCXXFLAGS: ${all_cxx_flags}"
"\nLINKER_FLAGS (shared) ${ALL_LD_FLAGS}" "\nLINKER_FLAGS (shared) ${ALL_LD_FLAGS}"
"\n" "\n"
"\nSource directory: ${CMAKE_CURRENT_SOURCE_DIR}" "\nSource directory: ${CMAKE_CURRENT_SOURCE_DIR}"
......
...@@ -56,16 +56,22 @@ CAF_POP_WARNINGS ...@@ -56,16 +56,22 @@ CAF_POP_WARNINGS
# pragma clang diagnostic ignored "-Wunused-const-variable" # pragma clang diagnostic ignored "-Wunused-const-variable"
#endif // __clang__ #endif // __clang__
CAF_BEGIN_TYPE_ID_BLOCK(curl_fuse, first_custom_type_id)
CAF_ADD_TYPE_ID(curl_fuse, std::vector<char>)
CAF_ADD_ATOM(curl_fuse, read_atom);
CAF_ADD_ATOM(curl_fuse, fail_atom);
CAF_ADD_ATOM(curl_fuse, next_atom);
CAF_ADD_ATOM(curl_fuse, reply_atom);
CAF_ADD_ATOM(curl_fuse, finished_atom);
CAF_END_TYPE_ID_BLOCK(curl_fuse)
using namespace caf; using namespace caf;
using buffer_type = std::vector<char>; using buffer_type = std::vector<char>;
CAF_MSG_TYPE_ADD_ATOM(read_atom);
CAF_MSG_TYPE_ADD_ATOM(fail_atom);
CAF_MSG_TYPE_ADD_ATOM(next_atom);
CAF_MSG_TYPE_ADD_ATOM(reply_atom);
CAF_MSG_TYPE_ADD_ATOM(finished_atom);
namespace color { namespace color {
// UNIX terminal color codes // UNIX terminal color codes
...@@ -320,11 +326,7 @@ std::atomic<bool> shutdown_flag{false}; ...@@ -320,11 +326,7 @@ std::atomic<bool> shutdown_flag{false};
struct config : actor_system_config { struct config : actor_system_config {
config() { config() {
add_message_type<read_atom>("read_atom"); init_global_meta_objects<curl_fuse_type_ids>();
add_message_type<fail_atom>("fail_atom");
add_message_type<next_atom>("next_atom");
add_message_type<reply_atom>("reply_atom");
add_message_type<finished_atom>("finished_atom");
} }
}; };
......
...@@ -11,6 +11,20 @@ ...@@ -11,6 +11,20 @@
#include "caf/all.hpp" #include "caf/all.hpp"
// --(rst-type-id-block-begin)--
struct foo;
struct foo2;
CAF_BEGIN_TYPE_ID_BLOCK(custom_types_1, first_custom_type_id)
CAF_ADD_TYPE_ID(custom_types_1, foo)
CAF_ADD_TYPE_ID(custom_types_1, foo2)
CAF_ADD_TYPE_ID(custom_types_1, std::pair<int32_t CAF_PP_COMMA int32_t>)
CAF_END_TYPE_ID_BLOCK(custom_types_1)
// --(rst-type-id-block-end)--
using std::cout; using std::cout;
using std::cerr; using std::cerr;
using std::endl; using std::endl;
...@@ -18,19 +32,17 @@ using std::vector; ...@@ -18,19 +32,17 @@ using std::vector;
using namespace caf; using namespace caf;
namespace { // --(rst-foo-begin)--
// POD struct foo
struct foo { struct foo {
std::vector<int> a; std::vector<int> a;
int b; int b;
}; };
// foo needs to be serializable
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, foo& x) { typename Inspector::result_type inspect(Inspector& f, foo& x) {
return f(meta::type_name("foo"), x.a, x.b); return f(meta::type_name("foo"), x.a, x.b);
} }
// --(rst-foo-end)--
// a pair of two ints // a pair of two ints
using foo_pair = std::pair<int, int>; using foo_pair = std::pair<int, int>;
...@@ -72,14 +84,14 @@ void testee(event_based_actor* self, size_t remaining) { ...@@ -72,14 +84,14 @@ void testee(event_based_actor* self, size_t remaining) {
); );
} }
// --(rst-config-begin)--
class config : public actor_system_config { class config : public actor_system_config {
public: public:
config() { config() {
add_message_type<foo>("foo"); init_global_meta_objects<custom_types_1_type_ids>();
add_message_type<foo2>("foo2");
add_message_type<foo_pair>("foo_pair");
} }
}; };
// --(rst-config-end)--
void caf_main(actor_system& system, const config&) { void caf_main(actor_system& system, const config&) {
// two variables for testing serialization // two variables for testing serialization
...@@ -118,6 +130,4 @@ void caf_main(actor_system& system, const config&) { ...@@ -118,6 +130,4 @@ void caf_main(actor_system& system, const config&) {
self->send(t, foo_pair2{3, 4}); self->send(t, foo_pair2{3, 4});
} }
} // namespace
CAF_MAIN() CAF_MAIN()
...@@ -6,14 +6,20 @@ ...@@ -6,14 +6,20 @@
#include "caf/all.hpp" #include "caf/all.hpp"
class foo;
CAF_BEGIN_TYPE_ID_BLOCK(custom_types_2, first_custom_type_id)
CAF_ADD_TYPE_ID(custom_types_2, foo)
CAF_END_TYPE_ID_BLOCK(custom_types_2)
using std::cout; using std::cout;
using std::endl; using std::endl;
using std::make_pair; using std::make_pair;
using namespace caf; using namespace caf;
namespace {
// a simple class using getter and setter member functions // a simple class using getter and setter member functions
class foo { class foo {
public: public:
...@@ -61,7 +67,7 @@ behavior testee(event_based_actor* self) { ...@@ -61,7 +67,7 @@ behavior testee(event_based_actor* self) {
class config : public actor_system_config { class config : public actor_system_config {
public: public:
config() { config() {
add_message_type<foo>("foo"); init_global_meta_objects<custom_types_2_type_ids>();
} }
}; };
...@@ -69,6 +75,4 @@ void caf_main(actor_system& system, const config&) { ...@@ -69,6 +75,4 @@ void caf_main(actor_system& system, const config&) {
anon_send(system.spawn(testee), foo{1, 2}); anon_send(system.spawn(testee), foo{1, 2});
} }
} // namespace
CAF_MAIN() CAF_MAIN()
// Showcases custom message types that cannot provide // Showcases custom message types that cannot provide
// friend access to the inspect() function. // friend access to the inspect() function.
// Manual refs: 20-49, 76-103 (TypeInspection)
#include <utility>
#include <iostream> #include <iostream>
#include <utility>
#include "caf/all.hpp" #include "caf/all.hpp"
class foo;
CAF_BEGIN_TYPE_ID_BLOCK(custom_types_3, first_custom_type_id)
CAF_ADD_TYPE_ID(custom_types_3, foo)
CAF_END_TYPE_ID_BLOCK(custom_types_3)
using std::cout; using std::cout;
using std::endl; using std::endl;
using std::make_pair; using std::make_pair;
using namespace caf; using namespace caf;
namespace { // Identical to our second custom type example, but no friend access for
// `inspect`.
// identical to our second custom type example, but // --(rst-foo-begin)--
// no friend access for `inspect`
class foo { class foo {
public: public:
foo(int a0 = 0, int b0 = 0) : a_(a0), b_(b0) { foo(int a0 = 0, int b0 = 0) : a_(a0), b_(b0) {
...@@ -47,19 +52,22 @@ private: ...@@ -47,19 +52,22 @@ private:
int a_; int a_;
int b_; int b_;
}; };
// --(rst-foo-end)--
// A lightweight scope guard implementation. // A lightweight scope guard implementation.
template <class Fun> template <class Fun>
class scope_guard { class scope_guard {
public: public:
scope_guard(Fun f) : fun_(std::move(f)), enabled_(true) { } scope_guard(Fun f) : fun_(std::move(f)), enabled_(true) {
}
scope_guard(scope_guard&& x) : fun_(std::move(x.fun_)), enabled_(x.enabled_) { scope_guard(scope_guard&& x) : fun_(std::move(x.fun_)), enabled_(x.enabled_) {
x.enabled_ = false; x.enabled_ = false;
} }
~scope_guard() { ~scope_guard() {
if (enabled_) fun_(); if (enabled_)
fun_();
} }
private: private:
...@@ -73,17 +81,12 @@ scope_guard<Fun> make_scope_guard(Fun f) { ...@@ -73,17 +81,12 @@ scope_guard<Fun> make_scope_guard(Fun f) {
return {std::move(f)}; return {std::move(f)};
} }
// --(rst-inspect-begin)--
template <class Inspector> template <class Inspector>
typename std::enable_if<Inspector::reads_state, typename Inspector::result_type inspect(Inspector& f, foo& x) {
typename Inspector::result_type>::type if constexpr (Inspector::reads_state) {
inspect(Inspector& f, foo& x) {
return f(meta::type_name("foo"), x.a(), x.b()); return f(meta::type_name("foo"), x.a(), x.b());
} } else {
template <class Inspector>
typename std::enable_if<Inspector::writes_state,
typename Inspector::result_type>::type
inspect(Inspector& f, foo& x) {
int a; int a;
int b; int b;
// write back to x at scope exit // write back to x at scope exit
...@@ -92,20 +95,20 @@ inspect(Inspector& f, foo& x) { ...@@ -92,20 +95,20 @@ inspect(Inspector& f, foo& x) {
x.set_b(b); x.set_b(b);
}); });
return f(meta::type_name("foo"), a, b); return f(meta::type_name("foo"), a, b);
}
} }
// --(rst-inspect-end)--
behavior testee(event_based_actor* self) { behavior testee(event_based_actor* self) {
return { return {
[=](const foo& x) { [=](const foo& x) { aout(self) << to_string(x) << endl; },
aout(self) << to_string(x) << endl;
}
}; };
} }
class config : public actor_system_config { class config : public actor_system_config {
public: public:
config() { config() {
add_message_type<foo>("foo"); init_global_meta_objects<custom_types_3_type_ids>();
} }
}; };
...@@ -113,6 +116,4 @@ void caf_main(actor_system& system, const config&) { ...@@ -113,6 +116,4 @@ void caf_main(actor_system& system, const config&) {
anon_send(system.spawn(testee), foo{1, 2}); anon_send(system.spawn(testee), foo{1, 2});
} }
} // namespace
CAF_MAIN() CAF_MAIN()
...@@ -13,6 +13,15 @@ ...@@ -13,6 +13,15 @@
#include "caf/all.hpp" #include "caf/all.hpp"
CAF_BEGIN_TYPE_ID_BLOCK(dining_philosophers, first_custom_type_id)
CAF_ADD_ATOM(dining_philosophers, take_atom);
CAF_ADD_ATOM(dining_philosophers, taken_atom);
CAF_ADD_ATOM(dining_philosophers, eat_atom);
CAF_ADD_ATOM(dining_philosophers, think_atom);
CAF_END_TYPE_ID_BLOCK(dining_philosophers)
using std::cerr; using std::cerr;
using std::cout; using std::cout;
using std::endl; using std::endl;
...@@ -23,10 +32,6 @@ using namespace caf; ...@@ -23,10 +32,6 @@ using namespace caf;
namespace { namespace {
// atoms for chopstick and philosopher interfaces // atoms for chopstick and philosopher interfaces
CAF_MSG_TYPE_ADD_ATOM(take_atom);
CAF_MSG_TYPE_ADD_ATOM(taken_atom);
CAF_MSG_TYPE_ADD_ATOM(eat_atom);
CAF_MSG_TYPE_ADD_ATOM(think_atom);
// a chopstick // a chopstick
using chopstick = typed_actor<replies_to<take_atom>::with<taken_atom, bool>, using chopstick = typed_actor<replies_to<take_atom>::with<taken_atom, bool>,
...@@ -172,10 +177,7 @@ private: ...@@ -172,10 +177,7 @@ private:
struct config : actor_system_config { struct config : actor_system_config {
config() { config() {
add_message_type<take_atom>("take_atom"); init_global_meta_objects<dining_philosophers_type_ids>();
add_message_type<taken_atom>("taken_atom");
add_message_type<eat_atom>("eat_atom");
add_message_type<think_atom>("think_atom");
} }
}; };
......
...@@ -14,19 +14,25 @@ ...@@ -14,19 +14,25 @@
#include "caf/event_based_actor.hpp" #include "caf/event_based_actor.hpp"
#include "caf/exec_main.hpp" #include "caf/exec_main.hpp"
#include "caf/function_view.hpp" #include "caf/function_view.hpp"
#include "caf/init_global_meta_objects.hpp"
#include "caf/policy/select_all.hpp" #include "caf/policy/select_all.hpp"
#include "caf/scoped_actor.hpp" #include "caf/scoped_actor.hpp"
#include "caf/stateful_actor.hpp" #include "caf/stateful_actor.hpp"
#include "caf/typed_actor.hpp" #include "caf/typed_actor.hpp"
#include "caf/typed_event_based_actor.hpp" #include "caf/typed_event_based_actor.hpp"
CAF_BEGIN_TYPE_ID_BLOCK(fan_out_request, first_custom_type_id)
CAF_ADD_ATOM(fan_out_request, row_atom);
CAF_ADD_ATOM(fan_out_request, column_atom);
CAF_ADD_ATOM(fan_out_request, average_atom);
CAF_END_TYPE_ID_BLOCK(fan_out_request)
using std::endl; using std::endl;
using std::chrono::seconds; using std::chrono::seconds;
using namespace caf; using namespace caf;
CAF_MSG_TYPE_ADD_ATOM(row_atom);
CAF_MSG_TYPE_ADD_ATOM(column_atom);
CAF_MSG_TYPE_ADD_ATOM(average_atom);
/// A simple actor for storing an integer value. /// A simple actor for storing an integer value.
using cell = typed_actor< using cell = typed_actor<
...@@ -124,9 +130,7 @@ std::ostream& operator<<(std::ostream& out, const expected<int>& x) { ...@@ -124,9 +130,7 @@ std::ostream& operator<<(std::ostream& out, const expected<int>& x) {
struct config : actor_system_config { struct config : actor_system_config {
config() { config() {
add_message_type<row_atom>("row_atom"); init_global_meta_objects<fan_out_request_type_ids>();
add_message_type<column_atom>("column_atom");
add_message_type<average_atom>("average_atom");
} }
}; };
......
...@@ -3,21 +3,21 @@ ...@@ -3,21 +3,21 @@
#include <cstdint> #include <cstdint>
#include <iostream> #include <iostream>
using std::endl; CAF_BEGIN_TYPE_ID_BLOCK(fixed_stack, first_custom_type_id)
using namespace caf;
CAF_ADD_ATOM(fixed_stack, pop_atom);
CAF_ADD_ATOM(fixed_stack, push_atom);
namespace { CAF_END_TYPE_ID_BLOCK(fixed_stack)
CAF_MSG_TYPE_ADD_ATOM(pop_atom); using std::endl;
CAF_MSG_TYPE_ADD_ATOM(push_atom); using namespace caf;
enum class fixed_stack_errc : uint8_t { enum class fixed_stack_errc : uint8_t {
push_to_full = 1, push_to_full = 1,
pop_from_empty, pop_from_empty,
}; };
} // namespace
namespace caf { namespace caf {
template <> template <>
...@@ -27,8 +27,6 @@ struct error_category<fixed_stack_errc> { ...@@ -27,8 +27,6 @@ struct error_category<fixed_stack_errc> {
} // namespace caf } // namespace caf
namespace {
class fixed_stack : public event_based_actor { class fixed_stack : public event_based_actor {
public: public:
fixed_stack(actor_config& cfg, size_t stack_size) fixed_stack(actor_config& cfg, size_t stack_size)
...@@ -75,6 +73,12 @@ private: ...@@ -75,6 +73,12 @@ private:
behavior empty_; behavior empty_;
}; };
struct config : actor_system_config {
config() {
init_global_meta_objects<fixed_stack_type_ids>();
}
};
void caf_main(actor_system& system) { void caf_main(actor_system& system) {
scoped_actor self{system}; scoped_actor self{system};
auto st = self->spawn<fixed_stack>(5u); auto st = self->spawn<fixed_stack>(5u);
...@@ -93,6 +97,4 @@ void caf_main(actor_system& system) { ...@@ -93,6 +97,4 @@ void caf_main(actor_system& system) {
self->send_exit(st, exit_reason::user_shutdown); self->send_exit(st, exit_reason::user_shutdown);
} }
} // namespace
CAF_MAIN() CAF_MAIN()
...@@ -274,7 +274,8 @@ void client_repl(actor_system& system, const config& cfg) { ...@@ -274,7 +274,8 @@ void client_repl(actor_system& system, const config& cfg) {
line = trim(std::move(line)); // ignore leading and trailing whitespaces line = trim(std::move(line)); // ignore leading and trailing whitespaces
std::vector<string> words; std::vector<string> words;
split(words, line, is_any_of(" "), token_compress_on); split(words, line, is_any_of(" "), token_compress_on);
if (!message_builder(words.begin(), words.end()).apply(eval)) auto msg = message_builder(words.begin(), words.end()).move_to_message();
if (!eval(msg))
usage(); usage();
} }
} }
......
...@@ -20,46 +20,47 @@ ...@@ -20,46 +20,47 @@
#include "caf/string_algorithms.hpp" #include "caf/string_algorithms.hpp"
using namespace std; CAF_BEGIN_TYPE_ID_BLOCK(group_chat, first_custom_type_id)
using namespace caf;
CAF_ADD_ATOM(group_chat, broadcast_atom);
namespace { CAF_END_TYPE_ID_BLOCK(group_chat)
CAF_MSG_TYPE_ADD_ATOM(broadcast_atom); using namespace caf;
struct line { struct line {
string str; std::string str;
}; };
istream& operator>>(istream& is, line& l) { std::istream& operator>>(std::istream& is, line& l) {
getline(is, l.str); std::getline(is, l.str);
return is; return is;
} }
behavior client(event_based_actor* self, const string& name) { behavior client(event_based_actor* self, const std::string& name) {
return { return {
[=](broadcast_atom, const string& message) { [=](broadcast_atom, const std::string& message) {
for (auto& dest : self->joined_groups()) { for (auto& dest : self->joined_groups()) {
self->send(dest, name + ": " + message); self->send(dest, name + ": " + message);
} }
}, },
[=](join_atom, const group& what) { [=](join_atom, const group& what) {
for (const auto& g : self->joined_groups()) { for (const auto& g : self->joined_groups()) {
cout << "*** leave " << to_string(g) << endl; std::cout << "*** leave " << to_string(g) << std::endl;
self->send(g, name + " has left the chatroom"); self->send(g, name + " has left the chatroom");
self->leave(g); self->leave(g);
} }
cout << "*** join " << to_string(what) << endl; std::cout << "*** join " << to_string(what) << std::endl;
self->join(what); self->join(what);
self->send(what, name + " has entered the chatroom"); self->send(what, name + " has entered the chatroom");
}, },
[=](const string& txt) { [=](const std::string& txt) {
// don't print own messages // don't print own messages
if (self->current_sender() != self) if (self->current_sender() != self)
cout << txt << endl; std::cout << txt << std::endl;
}, },
[=](const group_down_msg& g) { [=](const group_down_msg& g) {
cout << "*** chatroom offline: " << to_string(g.source) << endl; std::cout << "*** chatroom offline: " << to_string(g.source) << std::endl;
}, },
}; };
} }
...@@ -72,6 +73,7 @@ public: ...@@ -72,6 +73,7 @@ public:
bool server_mode = false; bool server_mode = false;
config() { config() {
init_global_meta_objects<group_chat_type_ids>();
opt_group{custom_options_, "global"} opt_group{custom_options_, "global"}
.add(name, "name,n", "set name") .add(name, "name,n", "set name")
.add(group_uris, "group,g", "join group") .add(group_uris, "group,g", "join group")
...@@ -84,48 +86,47 @@ void run_server(actor_system& system, const config& cfg) { ...@@ -84,48 +86,47 @@ void run_server(actor_system& system, const config& cfg) {
auto res = system.middleman().publish_local_groups(cfg.port); auto res = system.middleman().publish_local_groups(cfg.port);
if (!res) { if (!res) {
std::cerr << "*** publishing local groups failed: " std::cerr << "*** publishing local groups failed: "
<< system.render(res.error()) << endl; << system.render(res.error()) << std::endl;
return; return;
} }
cout << "*** listening at port " << *res << endl std::cout << "*** listening at port " << *res << std::endl
<< "*** press [enter] to quit" << endl; << "*** press [enter] to quit" << std::endl;
string dummy; std::string dummy;
std::getline(std::cin, dummy); std::getline(std::cin, dummy);
cout << "... cya" << endl; std::cout << "... cya" << std::endl;
} }
void run_client(actor_system& system, const config& cfg) { void run_client(actor_system& system, const config& cfg) {
auto name = cfg.name; auto name = cfg.name;
while (name.empty()) { while (name.empty()) {
cout << "please enter your name: " << flush; std::cout << "please enter your name: " << std::flush;
if (!getline(cin, name)) { if (!std::getline(std::cin, name)) {
cerr << "*** no name given... terminating" << endl; std::cerr << "*** no name given... terminating" << std::endl;
return; return;
} }
} }
cout << "*** starting client, type '/help' for a list of commands" << endl; std::cout << "*** starting client, type '/help' for a list of commands\n";
auto client_actor = system.spawn(client, name); auto client_actor = system.spawn(client, name);
for (auto& uri : cfg.group_uris) { for (auto& uri : cfg.group_uris) {
auto tmp = system.groups().get(uri); auto tmp = system.groups().get(uri);
if (tmp) if (tmp)
anon_send(client_actor, join_atom_v, std::move(*tmp)); anon_send(client_actor, join_atom_v, std::move(*tmp));
else else
cerr << R"(*** failed to parse ")" << uri << R"(" as group URI: )" std::cerr << R"(*** failed to parse ")" << uri << R"(" as group URI: )"
<< system.render(tmp.error()) << endl; << system.render(tmp.error()) << std::endl;
} }
istream_iterator<line> eof; std::istream_iterator<line> eof;
vector<string> words; std::vector<std::string> words;
for (istream_iterator<line> i(cin); i != eof; ++i) { for (std::istream_iterator<line> i{std::cin}; i != eof; ++i) {
auto send_input = [&] { auto send_input = [&] {
if (!i->str.empty()) if (!i->str.empty())
anon_send(client_actor, broadcast_atom_v, i->str); anon_send(client_actor, broadcast_atom_v, i->str);
}; };
words.clear(); words.clear();
split(words, i->str, is_any_of(" ")); split(words, i->str, is_any_of(" "));
auto res message_handler f{
= message_builder(words.begin(), words.end()) [&](const std::string& cmd, const std::string& mod,
.apply( const std::string& id) {
{[&](const string& cmd, const string& mod, const string& id) {
if (cmd == "/join") { if (cmd == "/join") {
auto grp = system.groups().get(mod, id); auto grp = system.groups().get(mod, id);
if (grp) if (grp)
...@@ -134,19 +135,21 @@ void run_client(actor_system& system, const config& cfg) { ...@@ -134,19 +135,21 @@ void run_client(actor_system& system, const config& cfg) {
send_input(); send_input();
} }
}, },
[&](const string& cmd) { [&](const std::string& cmd) {
if (cmd == "/quit") { if (cmd == "/quit") {
cin.setstate(ios_base::eofbit); std::cin.setstate(std::ios_base::eofbit);
} else if (cmd[0] == '/') { } else if (cmd[0] == '/') {
cout << "*** available commands:\n" std::cout << "*** available commands:\n"
" /join <module> <group> join a new chat channel\n" " /join <module> <group> join a new chat channel\n"
" /quit quit the program\n" " /quit quit the program\n"
" /help print this text\n" " /help print this text\n";
<< flush;
} else { } else {
send_input(); send_input();
} }
}}); },
};
auto msg = message_builder(words.begin(), words.end()).move_to_message();
auto res = f(msg);
if (!res) if (!res)
send_input(); send_input();
} }
...@@ -159,6 +162,4 @@ void caf_main(actor_system& system, const config& cfg) { ...@@ -159,6 +162,4 @@ void caf_main(actor_system& system, const config& cfg) {
f(system, cfg); f(system, cfg);
} }
} // namespace
CAF_MAIN(io::middleman) CAF_MAIN(io::middleman)
...@@ -7,9 +7,6 @@ ...@@ -7,9 +7,6 @@
// Run client at the same host: // Run client at the same host:
// - remote_spawn -H localhost -p 4242 // - remote_spawn -H localhost -p 4242
// Manual refs: 33-34, 98-109 (ConfiguringActorApplications)
// 123-137 (RemoteSpawn)
#include <array> #include <array>
#include <cassert> #include <cassert>
#include <functional> #include <functional>
...@@ -21,6 +18,18 @@ ...@@ -21,6 +18,18 @@
#include "caf/all.hpp" #include "caf/all.hpp"
#include "caf/io/all.hpp" #include "caf/io/all.hpp"
// --(rst-calculator-begin)--
using calculator
= caf::typed_actor<caf::replies_to<caf::add_atom, int, int>::with<int>,
caf::replies_to<caf::sub_atom, int, int>::with<int>>;
// --(rst-calculator-end)--
CAF_BEGIN_TYPE_ID_BLOCK(remote_spawn, first_custom_type_id)
CAF_ADD_TYPE_ID(remote_spawn, calculator)
CAF_END_TYPE_ID_BLOCK(remote_spawn)
using std::cerr; using std::cerr;
using std::cout; using std::cout;
using std::endl; using std::endl;
...@@ -28,11 +37,6 @@ using std::string; ...@@ -28,11 +37,6 @@ using std::string;
using namespace caf; using namespace caf;
namespace {
using calculator = typed_actor<replies_to<add_atom, int, int>::with<int>,
replies_to<sub_atom, int, int>::with<int>>;
calculator::behavior_type calculator_fun(calculator::pointer self) { calculator::behavior_type calculator_fun(calculator::pointer self) {
return { return {
[=](add_atom, int a, int b) -> int { [=](add_atom, int a, int b) -> int {
...@@ -98,6 +102,7 @@ void client_repl(function_view<calculator> f) { ...@@ -98,6 +102,7 @@ void client_repl(function_view<calculator> f) {
struct config : actor_system_config { struct config : actor_system_config {
config() { config() {
add_actor_type("calculator", calculator_fun); add_actor_type("calculator", calculator_fun);
init_global_meta_objects<remote_spawn_type_ids>();
opt_group{custom_options_, "global"} opt_group{custom_options_, "global"}
.add(port, "port,p", "set port") .add(port, "port,p", "set port")
.add(host, "host,H", "set node (ignored in server mode)") .add(host, "host,H", "set node (ignored in server mode)")
...@@ -119,6 +124,7 @@ void server(actor_system& system, const config& cfg) { ...@@ -119,6 +124,7 @@ void server(actor_system& system, const config& cfg) {
getchar(); getchar();
} }
// --(rst-client-begin)--
void client(actor_system& system, const config& cfg) { void client(actor_system& system, const config& cfg) {
auto node = system.middleman().connect(cfg.host, cfg.port); auto node = system.middleman().connect(cfg.host, cfg.port);
if (!node) { if (!node) {
...@@ -140,12 +146,11 @@ void client(actor_system& system, const config& cfg) { ...@@ -140,12 +146,11 @@ void client(actor_system& system, const config& cfg) {
// be a good citizen and terminate remotely spawned actor before exiting // be a good citizen and terminate remotely spawned actor before exiting
anon_send_exit(*worker, exit_reason::kill); anon_send_exit(*worker, exit_reason::kill);
} }
// --(rst-client-end)--
void caf_main(actor_system& system, const config& cfg) { void caf_main(actor_system& system, const config& cfg) {
auto f = cfg.server_mode ? server : client; auto f = cfg.server_mode ? server : client;
f(system, cfg); f(system, cfg);
} }
} // namespace
CAF_MAIN(io::middleman) CAF_MAIN(io::middleman)
...@@ -2,22 +2,28 @@ ...@@ -2,22 +2,28 @@
* Basic, non-interactive streaming example for processing integers. * * Basic, non-interactive streaming example for processing integers. *
******************************************************************************/ ******************************************************************************/
// Manual refs: lines 17-48, 50-83, 85-114, 128-132 (Streaming)
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include "caf/all.hpp" #include "caf/all.hpp"
CAF_BEGIN_TYPE_ID_BLOCK(integer_stream, first_custom_type_id)
CAF_ADD_TYPE_ID(integer_stream, caf::stream<int32_t>)
CAF_ADD_TYPE_ID(integer_stream, std::vector<int32_t>)
CAF_END_TYPE_ID_BLOCK(integer_stream)
using std::endl; using std::endl;
using namespace caf; using namespace caf;
namespace { namespace {
// --(rst-source-begin)--
// Simple source for generating a stream of integers from [0, n). // Simple source for generating a stream of integers from [0, n).
behavior int_source(event_based_actor* self) { behavior int_source(event_based_actor* self) {
return { return {
[=](open_atom, int n) { [=](open_atom, int32_t n) {
// Produce at least one value. // Produce at least one value.
if (n <= 0) if (n <= 0)
n = 1; n = 1;
...@@ -28,7 +34,7 @@ behavior int_source(event_based_actor* self) { ...@@ -28,7 +34,7 @@ behavior int_source(event_based_actor* self) {
self, self,
// Initializer. The type of the first argument (state) is freely // Initializer. The type of the first argument (state) is freely
// chosen. If no state is required, `caf::unit_t` can be used here. // chosen. If no state is required, `caf::unit_t` can be used here.
[](int& x) { x = 0; }, [](int32_t& x) { x = 0; },
// Generator. This function is called by CAF to produce new stream // Generator. This function is called by CAF to produce new stream
// elements for downstream actors. The `x` argument is our state again // elements for downstream actors. The `x` argument is our state again
// (with our freely chosen type). The second argument `out` points to // (with our freely chosen type). The second argument `out` points to
...@@ -36,21 +42,23 @@ behavior int_source(event_based_actor* self) { ...@@ -36,21 +42,23 @@ behavior int_source(event_based_actor* self) {
// elements downstream actors receive in this stream. Finally, `num` is // elements downstream actors receive in this stream. Finally, `num` is
// a hint from CAF how many elements we should ideally insert into // a hint from CAF how many elements we should ideally insert into
// `out`. We can always insert fewer or more items. // `out`. We can always insert fewer or more items.
[n](int& x, downstream<int>& out, size_t num) { [n](int32_t& x, downstream<int32_t>& out, size_t num) {
auto max_x = std::min(x + static_cast<int>(num), n); auto max_x = std::min(x + static_cast<int>(num), n);
for (; x < max_x; ++x) for (; x < max_x; ++x)
out.push(x); out.push(x);
}, },
// Predicate. This function tells CAF when we reached the end. // Predicate. This function tells CAF when we reached the end.
[n](const int& x) { return x == n; }); [n](const int32_t& x) { return x == n; });
}, },
}; };
} }
// --(rst-source-end)--
// --(rst-stage-begin)--
// Simple stage that only selects even numbers. // Simple stage that only selects even numbers.
behavior int_selector(event_based_actor* self) { behavior int_selector(event_based_actor* self) {
return { return {
[=](stream<int> in) { [=](stream<int32_t> in) {
// Create a stream manager for implementing a stream stage. Similar to // Create a stream manager for implementing a stream stage. Similar to
// `make_source`, we need three functions: initialzer, processor, and // `make_source`, we need three functions: initialzer, processor, and
// finalizer. // finalizer.
...@@ -64,7 +72,7 @@ behavior int_selector(event_based_actor* self) { ...@@ -64,7 +72,7 @@ behavior int_selector(event_based_actor* self) {
}, },
// Processor. This function takes individual input elements as `val` // Processor. This function takes individual input elements as `val`
// and forwards even integers to `out`. // and forwards even integers to `out`.
[](unit_t&, downstream<int>& out, int val) { [](unit_t&, downstream<int32_t>& out, int32_t val) {
if (val % 2 == 0) if (val % 2 == 0)
out.push(val); out.push(val);
}, },
...@@ -81,10 +89,12 @@ behavior int_selector(event_based_actor* self) { ...@@ -81,10 +89,12 @@ behavior int_selector(event_based_actor* self) {
}, },
}; };
} }
// --(rst-stage-end)--
// --(rst-sink-begin)--
behavior int_sink(event_based_actor* self) { behavior int_sink(event_based_actor* self) {
return { return {
[=](stream<int> in) { [=](stream<int32_t> in) {
// Create a stream manager for implementing a stream sink. Once more, we // Create a stream manager for implementing a stream sink. Once more, we
// have to provide three functions: Initializer, Consumer, Finalizer. // have to provide three functions: Initializer, Consumer, Finalizer.
return attach_stream_sink( return attach_stream_sink(
...@@ -99,9 +109,9 @@ behavior int_sink(event_based_actor* self) { ...@@ -99,9 +109,9 @@ behavior int_sink(event_based_actor* self) {
}, },
// Consumer. Takes individual input elements as `val` and stores them // Consumer. Takes individual input elements as `val` and stores them
// in our history. // in our history.
[](std::vector<int>& xs, int val) { xs.emplace_back(val); }, [](std::vector<int32_t>& xs, int32_t val) { xs.emplace_back(val); },
// Finalizer. Allows us to run cleanup code once the stream terminates. // Finalizer. Allows us to run cleanup code once the stream terminates.
[=](std::vector<int>& xs, const error& err) { [=](std::vector<int32_t>& xs, const error& err) {
if (err) { if (err) {
aout(self) << "int_sink aborted with error: " << err << std::endl; aout(self) << "int_sink aborted with error: " << err << std::endl;
} else { } else {
...@@ -112,18 +122,21 @@ behavior int_sink(event_based_actor* self) { ...@@ -112,18 +122,21 @@ behavior int_sink(event_based_actor* self) {
}, },
}; };
} }
// --(rst-sink-end)--
struct config : actor_system_config { struct config : actor_system_config {
config() { config() {
init_global_meta_objects<integer_stream_type_ids>();
opt_group{custom_options_, "global"} opt_group{custom_options_, "global"}
.add(with_stage, "with-stage,s", "use a stage for filtering odd numbers") .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"); .add(n, "num-values,n", "number of values produced by the source");
} }
bool with_stage = false; bool with_stage = false;
int n = 100; int32_t n = 100;
}; };
// --(rst-main-begin)--
void caf_main(actor_system& sys, const config& cfg) { void caf_main(actor_system& sys, const config& cfg) {
auto src = sys.spawn(int_source); auto src = sys.spawn(int_source);
auto snk = sys.spawn(int_sink); auto snk = sys.spawn(int_sink);
...@@ -131,6 +144,7 @@ void caf_main(actor_system& sys, const config& cfg) { ...@@ -131,6 +144,7 @@ void caf_main(actor_system& sys, const config& cfg) {
: snk * src; : snk * src;
anon_send(pipeline, open_atom_v, cfg.n); anon_send(pipeline, open_atom_v, cfg.n);
} }
// --(rst-main-end)--
} // namespace } // namespace
......
...@@ -69,6 +69,7 @@ set(CAF_CORE_SOURCES ...@@ -69,6 +69,7 @@ set(CAF_CORE_SOURCES
src/detail/get_root_uuid.cpp src/detail/get_root_uuid.cpp
src/detail/ini_consumer.cpp src/detail/ini_consumer.cpp
src/detail/invoke_result_visitor.cpp src/detail/invoke_result_visitor.cpp
src/detail/message_builder_element.cpp
src/detail/message_data.cpp src/detail/message_data.cpp
src/detail/meta_object.cpp src/detail/meta_object.cpp
src/detail/parse.cpp src/detail/parse.cpp
......
...@@ -104,7 +104,7 @@ public: ...@@ -104,7 +104,7 @@ public:
// -- overridden member functions -------------------------------------------- // -- overridden member functions --------------------------------------------
result_type begin_object(uint16_t& typenr, std::string& name); result_type begin_object(type_id_t& type);
result_type end_object() noexcept; result_type end_object() noexcept;
......
...@@ -95,7 +95,7 @@ public: ...@@ -95,7 +95,7 @@ public:
// -- interface functions ---------------------------------------------------- // -- interface functions ----------------------------------------------------
error_code<sec> begin_object(uint16_t nr, string_view name); error_code<sec> begin_object(type_id_t type);
error_code<sec> end_object(); error_code<sec> end_object();
......
...@@ -57,8 +57,7 @@ public: ...@@ -57,8 +57,7 @@ public:
// -- interface functions ---------------------------------------------------- // -- interface functions ----------------------------------------------------
/// Begins processing of an object. /// Begins processing of an object.
virtual result_type begin_object(uint16_t& typenr, std::string& type_name) virtual result_type begin_object(type_id_t& type) = 0;
= 0;
/// Ends processing of an object. /// Ends processing of an object.
virtual result_type end_object() = 0; virtual result_type end_object() = 0;
......
...@@ -21,25 +21,25 @@ ...@@ -21,25 +21,25 @@
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include "caf/byte.hpp"
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
namespace caf::detail { namespace caf::detail {
CAF_CORE_EXPORT void CAF_CORE_EXPORT void
append_hex(std::string& result, const uint8_t* xs, size_t n); append_hex(std::string& result, const byte* xs, size_t n);
template <class T> template <class T>
enable_if_t<has_data_member<T>::value> enable_if_t<has_data_member<T>::value>
append_hex(std::string& result, const T& x) { append_hex(std::string& result, const T& x) {
return append_hex(result, reinterpret_cast<const uint8_t*>(x.data()), return append_hex(result, reinterpret_cast<const byte*>(x.data()), x.size());
x.size());
} }
template <class T> template <class T>
enable_if_t<std::is_integral<T>::value> enable_if_t<std::is_integral<T>::value>
append_hex(std::string& result, const T& x) { append_hex(std::string& result, const T& x) {
return append_hex(result, reinterpret_cast<const uint8_t*>(&x), sizeof(T)); return append_hex(result, reinterpret_cast<const byte*>(&x), sizeof(T));
} }
} // namespace caf::detail } // namespace caf::detail
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "caf/deserializer.hpp" #include "caf/deserializer.hpp"
#include "caf/detail/meta_object.hpp" #include "caf/detail/meta_object.hpp"
#include "caf/detail/padded_size.hpp" #include "caf/detail/padded_size.hpp"
#include "caf/detail/stringification_inspector.hpp"
#include "caf/error.hpp" #include "caf/error.hpp"
#include "caf/serializer.hpp" #include "caf/serializer.hpp"
...@@ -54,6 +55,10 @@ meta_object make_meta_object(const char* type_name) { ...@@ -54,6 +55,10 @@ meta_object make_meta_object(const char* type_name) {
[](caf::deserializer& source, void* ptr) { [](caf::deserializer& source, void* ptr) {
return source(*reinterpret_cast<T*>(ptr)); return source(*reinterpret_cast<T*>(ptr));
}, },
[](std::string& buf, const void* ptr) {
stringification_inspector f{buf};
f(*reinterpret_cast<const T*>(ptr));
},
}; };
} }
......
...@@ -31,7 +31,7 @@ namespace caf::detail { ...@@ -31,7 +31,7 @@ namespace caf::detail {
/// later. /// later.
class CAF_CORE_EXPORT message_builder_element { class CAF_CORE_EXPORT message_builder_element {
public: public:
virtual ~message_builder_element() noexcept; virtual ~message_builder_element();
/// Uses placement new to create a copy of the wrapped value at given memory /// Uses placement new to create a copy of the wrapped value at given memory
/// region. /// region.
......
...@@ -147,7 +147,7 @@ void message_data_init(byte* storage, T&& x, Ts&&... xs) { ...@@ -147,7 +147,7 @@ void message_data_init(byte* storage, T&& x, Ts&&... xs) {
// TODO: exception safety: if any constructor throws, we need to unwind the // TODO: exception safety: if any constructor throws, we need to unwind the
// stack here and call destructors. // stack here and call destructors.
using type = strip_and_convert_t<T>; using type = strip_and_convert_t<T>;
new (storage) strip_and_convert_t<T>(std::forward<T>(x)); new (storage) type(std::forward<T>(x));
message_data_init(storage + padded_size_v<type>, std::forward<Ts>(xs)...); message_data_init(storage + padded_size_v<type>, std::forward<Ts>(xs)...);
} }
......
...@@ -58,6 +58,9 @@ struct meta_object { ...@@ -58,6 +58,9 @@ struct meta_object {
/// Applies an object to a generic deserializer. /// Applies an object to a generic deserializer.
caf::error (*load)(caf::deserializer&, void*); caf::error (*load)(caf::deserializer&, void*);
/// Appends a string representation of an object to a buffer.
void (*stringify)(std::string&, const void*);
}; };
/// Convenience function for calling `meta.save(sink, obj)`. /// Convenience function for calling `meta.save(sink, obj)`.
...@@ -81,7 +84,7 @@ load(const meta_object& meta, caf::binary_deserializer& source, void* obj); ...@@ -81,7 +84,7 @@ load(const meta_object& meta, caf::binary_deserializer& source, void* obj);
CAF_CORE_EXPORT span<const meta_object> global_meta_objects(); CAF_CORE_EXPORT span<const meta_object> global_meta_objects();
/// Returns the global meta object for given type ID. /// Returns the global meta object for given type ID.
CAF_CORE_EXPORT meta_object& global_meta_object(type_id_t id); CAF_CORE_EXPORT const meta_object* global_meta_object(type_id_t id);
/// Clears the array for storing global meta objects. /// Clears the array for storing global meta objects.
/// @warning intended for unit testing only! /// @warning intended for unit testing only!
......
...@@ -33,7 +33,7 @@ public: ...@@ -33,7 +33,7 @@ public:
return result_; return result_;
} }
result_type begin_object(uint16_t typenr, string_view type_name) override; result_type begin_object(type_id_t) override;
result_type end_object() override; result_type end_object() override;
......
...@@ -60,7 +60,7 @@ public: ...@@ -60,7 +60,7 @@ public:
// -- serializer interface --------------------------------------------------- // -- serializer interface ---------------------------------------------------
void begin_object(uint16_t, string_view) { void begin_object(type_id_t) {
// nop // nop
} }
......
...@@ -20,12 +20,13 @@ ...@@ -20,12 +20,13 @@
#include <cstdlib> #include <cstdlib>
#include "caf/detail/core_export.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/type_id.hpp" #include "caf/type_id.hpp"
namespace caf::detail { namespace caf::detail {
class type_id_list_builder { class CAF_CORE_EXPORT type_id_list_builder {
public: public:
static constexpr size_t block_size = 8; static constexpr size_t block_size = 8;
......
...@@ -268,7 +268,7 @@ template <class T> ...@@ -268,7 +268,7 @@ template <class T>
std::string to_string(const intrusive_ptr<T>& x) { std::string to_string(const intrusive_ptr<T>& x) {
std::string result; std::string result;
auto v = reinterpret_cast<uintptr_t>(x.get()); auto v = reinterpret_cast<uintptr_t>(x.get());
detail::append_hex(result, reinterpret_cast<uint8_t*>(&v), sizeof(v)); detail::append_hex(result, reinterpret_cast<byte*>(&v), sizeof(v));
return result; return result;
} }
......
...@@ -182,14 +182,15 @@ template <class... Ts> ...@@ -182,14 +182,15 @@ template <class... Ts>
message make_message(Ts&&... xs) { message make_message(Ts&&... xs) {
using namespace detail; using namespace detail;
static_assert((!std::is_pointer<strip_and_convert_t<Ts>>::value && ...)); static_assert((!std::is_pointer<strip_and_convert_t<Ts>>::value && ...));
static constexpr size_t data_size = sizeof(message_data) static_assert((is_complete<type_id<strip_and_convert_t<Ts>>> && ...));
+ (padded_size_v<std::decay_t<Ts>> + ...); static constexpr size_t data_size
= sizeof(message_data) + (padded_size_v<strip_and_convert_t<Ts>> + ...);
auto types = make_type_id_list<strip_and_convert_t<Ts>...>(); auto types = make_type_id_list<strip_and_convert_t<Ts>...>();
auto vptr = malloc(data_size); auto vptr = malloc(data_size);
if (vptr == nullptr) if (vptr == nullptr)
throw std::bad_alloc(); throw std::bad_alloc();
auto raw_ptr = new (vptr) message_data(types); auto raw_ptr = new (vptr) message_data(types);
intrusive_cow_ptr<message_data> ptr{}; intrusive_cow_ptr<message_data> ptr{raw_ptr, false};
message_data_init(raw_ptr->storage(), std::forward<Ts>(xs)...); message_data_init(raw_ptr->storage(), std::forward<Ts>(xs)...);
return message{std::move(ptr)}; return message{std::move(ptr)};
} }
......
...@@ -58,8 +58,9 @@ public: ...@@ -58,8 +58,9 @@ public:
/// Adds `x` to the elements of the buffer. /// Adds `x` to the elements of the buffer.
template <class T> template <class T>
message_builder& append(T&& x) { message_builder& append(T&& x) {
using value_type = detail::strip_and_convert<T>; using namespace detail;
static_assert(detail::sendable<value_type>); using value_type = strip_and_convert_t<T>;
static_assert(sendable<value_type>);
types_.push_back(type_id_v<value_type>); types_.push_back(type_id_v<value_type>);
elements_.emplace_back(make_message_builder_element(std::forward<T>(x))); elements_.emplace_back(make_message_builder_element(std::forward<T>(x)));
return *this; return *this;
......
...@@ -62,7 +62,7 @@ public: ...@@ -62,7 +62,7 @@ public:
/// Begins processing of an object. Saves the type information /// Begins processing of an object. Saves the type information
/// to the underlying storage. /// to the underlying storage.
virtual result_type begin_object(uint16_t typenr, string_view type_name) = 0; virtual result_type begin_object(type_id_t type) = 0;
/// Ends processing of an object. /// Ends processing of an object.
virtual result_type end_object() = 0; virtual result_type end_object() = 0;
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <utility> #include <utility>
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/detail/pp.hpp"
#include "caf/detail/squashed_int.hpp" #include "caf/detail/squashed_int.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/meta/type_name.hpp" #include "caf/meta/type_name.hpp"
...@@ -120,8 +121,25 @@ constexpr type_id_t first_custom_type_id = 200; ...@@ -120,8 +121,25 @@ constexpr type_id_t first_custom_type_id = 200;
: type_name<fully_qualified_name> {}; \ : type_name<fully_qualified_name> {}; \
} }
/// Creates a new tag type (atom) in the global namespace and assigns the next
/// free type ID to it.
#define CAF_ADD_ATOM_2(project_name, atom_name) \
struct atom_name {}; \
static constexpr atom_name atom_name##_v = atom_name{}; \
[[maybe_unused]] constexpr bool operator==(atom_name, atom_name) { \
return true; \
} \
[[maybe_unused]] constexpr bool operator!=(atom_name, atom_name) { \
return false; \
} \
template <class Inspector> \
auto inspect(Inspector& f, atom_name&) { \
return f(caf::meta::type_name(#atom_name)); \
} \
CAF_ADD_TYPE_ID(project_name, atom_name)
/// Creates a new tag type (atom) and assigns the next free type ID to it. /// Creates a new tag type (atom) and assigns the next free type ID to it.
#define CAF_ADD_ATOM(project_name, atom_namespace, atom_name) \ #define CAF_ADD_ATOM_3(project_name, atom_namespace, atom_name) \
namespace atom_namespace { \ namespace atom_namespace { \
struct atom_name {}; \ struct atom_name {}; \
static constexpr atom_name atom_name##_v = atom_name{}; \ static constexpr atom_name atom_name##_v = atom_name{}; \
...@@ -138,6 +156,15 @@ constexpr type_id_t first_custom_type_id = 200; ...@@ -138,6 +156,15 @@ constexpr type_id_t first_custom_type_id = 200;
} \ } \
CAF_ADD_TYPE_ID(project_name, atom_namespace ::atom_name) CAF_ADD_TYPE_ID(project_name, atom_namespace ::atom_name)
#ifdef CAF_MSVC
# define CAF_ADD_ATOM(...) \
CAF_PP_CAT(CAF_PP_OVERLOAD(CAF_ADD_ATOM_, __VA_ARGS__)(__VA_ARGS__), \
CAF_PP_EMPTY())
#else
# define CAF_ADD_ATOM(...) \
CAF_PP_OVERLOAD(CAF_ADD_ATOM_, __VA_ARGS__)(__VA_ARGS__)
#endif
/// Finalizes a code block for registering custom types to CAF. Stores the last /// 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`. /// type ID used by the project as `caf::${project_name}_last_type_id`.
#define CAF_END_TYPE_ID_BLOCK(project_name) \ #define CAF_END_TYPE_ID_BLOCK(project_name) \
......
...@@ -53,13 +53,16 @@ public: ...@@ -53,13 +53,16 @@ public:
} }
/// Returns the number of elements in the list. /// Returns the number of elements in the list.
/// @pre `data() != nullptr`
constexpr size_t size() const noexcept { constexpr size_t size() const noexcept {
return data_[0]; return data_[0];
} }
/// Returns `size() == 0`.
constexpr bool empty() const noexcept {
return size() == 0;
}
/// Returns the type ID at `index`. /// Returns the type ID at `index`.
/// @pre `data() != nullptr`
constexpr type_id_t operator[](size_t index) const noexcept { constexpr type_id_t operator[](size_t index) const noexcept {
return data_[index + 1]; return data_[index + 1];
} }
...@@ -86,14 +89,14 @@ private: ...@@ -86,14 +89,14 @@ private:
/// @private /// @private
template <class... Ts> template <class... Ts>
struct make_type_id_list_helper { struct make_type_id_list_helper {
static constexpr inline type_id_t data[] static inline type_id_t data[] = {static_cast<type_id_t>(sizeof...(Ts)),
= {static_cast<type_id_t>(sizeof...(Ts)), type_id_v<Ts>...}; type_id_v<Ts>...};
}; };
/// Constructs a ::type_id_list from the template parameter pack `Ts`. /// Constructs a ::type_id_list from the template parameter pack `Ts`.
/// @relates type_id_list /// @relates type_id_list
template <class... Ts> template <class... Ts>
constexpr type_id_list make_type_id_list() { type_id_list make_type_id_list() {
return type_id_list{make_type_id_list_helper<Ts...>::data}; return type_id_list{make_type_id_list_helper<Ts...>::data};
} }
......
...@@ -68,14 +68,8 @@ binary_deserializer::binary_deserializer(actor_system& sys) noexcept ...@@ -68,14 +68,8 @@ binary_deserializer::binary_deserializer(actor_system& sys) noexcept
// nop // nop
} }
result_type binary_deserializer::begin_object(uint16_t& nr, std::string& name) { result_type binary_deserializer::begin_object(type_id_t& type) {
name.clear(); return apply(type);
if (auto err = apply(nr))
return err;
if (nr == 0)
if (auto err = apply(name))
return err;
return none;
} }
result_type binary_deserializer::end_object() noexcept { result_type binary_deserializer::end_object() noexcept {
......
...@@ -49,10 +49,8 @@ void binary_serializer::skip(size_t num_bytes) { ...@@ -49,10 +49,8 @@ void binary_serializer::skip(size_t num_bytes) {
write_pos_ += num_bytes; write_pos_ += num_bytes;
} }
error_code<sec> binary_serializer::begin_object(uint16_t nr, string_view name) { error_code<sec> binary_serializer::begin_object(type_id_t type) {
apply(nr); apply(type);
if (nr == 0)
apply(name);
return none; return none;
} }
......
...@@ -20,15 +20,15 @@ ...@@ -20,15 +20,15 @@
namespace caf::detail { namespace caf::detail {
void append_hex(std::string& result, const uint8_t* xs, size_t n) { void append_hex(std::string& result, const byte* xs, size_t n) {
if (n == 0) { if (n == 0) {
result += "00"; result += "<empty>";
return; return;
} }
auto tbl = "0123456789ABCDEF"; auto tbl = "0123456789ABCDEF";
char buf[3] = {0, 0, 0}; char buf[3] = {0, 0, 0};
for (size_t i = 0; i < n; ++i) { for (size_t i = 0; i < n; ++i) {
auto c = xs[i]; auto c = to_integer<uint8_t>(xs[i]);
buf[0] = tbl[c >> 4]; buf[0] = tbl[c >> 4];
buf[1] = tbl[c & 0x0F]; buf[1] = tbl[c & 0x0F];
result += buf; result += buf;
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "caf/detail/append_percent_encoded.hpp" #include "caf/detail/append_percent_encoded.hpp"
#include "caf/byte.hpp"
#include "caf/config.hpp" #include "caf/config.hpp"
#include "caf/detail/append_hex.hpp" #include "caf/detail/append_hex.hpp"
#include "caf/string_view.hpp" #include "caf/string_view.hpp"
...@@ -33,7 +34,7 @@ void append_percent_encoded(std::string& str, string_view x, bool is_path) { ...@@ -33,7 +34,7 @@ void append_percent_encoded(std::string& str, string_view x, bool is_path) {
str += ch; str += ch;
break; break;
} }
CAF_ANNOTATE_FALLTHROUGH; [[fallthrough]];
case ' ': case ' ':
case '?': case '?':
case '#': case '#':
...@@ -53,7 +54,7 @@ void append_percent_encoded(std::string& str, string_view x, bool is_path) { ...@@ -53,7 +54,7 @@ void append_percent_encoded(std::string& str, string_view x, bool is_path) {
case ';': case ';':
case '=': case '=':
str += '%'; str += '%';
append_hex(str, reinterpret_cast<uint8_t*>(&ch), 1); append_hex(str, reinterpret_cast<byte*>(&ch), 1);
break; break;
default: default:
str += ch; str += ch;
......
...@@ -76,9 +76,10 @@ span<const meta_object> global_meta_objects() { ...@@ -76,9 +76,10 @@ span<const meta_object> global_meta_objects() {
return {meta_objects, meta_objects_size}; return {meta_objects, meta_objects_size};
} }
meta_object& global_meta_object(type_id_t id) { const meta_object* global_meta_object(type_id_t id) {
CAF_ASSERT(id < meta_objects_size); CAF_ASSERT(id < meta_objects_size);
return meta_objects[id]; auto& meta = meta_objects[id];
return meta.type_name != nullptr ? &meta : nullptr;
} }
void clear_global_meta_objects() { void clear_global_meta_objects() {
......
...@@ -26,11 +26,8 @@ ...@@ -26,11 +26,8 @@
namespace caf::detail { namespace caf::detail {
error serialized_size_inspector::begin_object(uint16_t nr, string_view name) { error serialized_size_inspector::begin_object(type_id_t type) {
if (nr != 0) return apply(type);
return apply(nr);
apply(nr);
return apply(name);
} }
error serialized_size_inspector::end_object() { error serialized_size_inspector::end_object() {
......
...@@ -75,7 +75,7 @@ inbound_path::inbound_path(stream_manager_ptr mgr_ptr, stream_slots id, ...@@ -75,7 +75,7 @@ inbound_path::inbound_path(stream_manager_ptr mgr_ptr, stream_slots id,
mgr->register_input_path(this); mgr->register_input_path(this);
CAF_STREAM_LOG_DEBUG(mgr->self()->name() CAF_STREAM_LOG_DEBUG(mgr->self()->name()
<< "opens input stream with element type" << "opens input stream with element type"
<< detail::global_meta_object(in_type).type_name << detail::global_meta_object(in_type)->type_name
<< "at slot" << id.receiver << "from" << hdl); << "at slot" << id.receiver << "from" << hdl);
if (auto str = get_if<std::string>(&self()->system().config(), if (auto str = get_if<std::string>(&self()->system().config(),
"stream.credit-policy")) { "stream.credit-policy")) {
......
...@@ -154,9 +154,28 @@ error_code<sec> inspect(binary_deserializer& source, message& msg) { ...@@ -154,9 +154,28 @@ error_code<sec> inspect(binary_deserializer& source, message& msg) {
return msg.load(source); return msg.load(source);
} }
std::string to_string(const message& ) { std::string to_string(const message& msg) {
// TODO: implement me if (msg.empty())
return ""; return "<empty-message>";
std::string result;
result += '(';
auto types = msg.types();
if (!types.empty()) {
auto ptr = msg.cdata().storage();
auto meta = detail::global_meta_object(types[0]);
CAF_ASSERT(meta != nullptr);
meta->stringify(result, ptr);
ptr += meta->padded_size;
for (size_t index = 1; index < types.size(); ++index) {
result += ", ";
meta = detail::global_meta_object(types[index]);
CAF_ASSERT(meta != nullptr);
meta->stringify(result, ptr);
ptr += meta->padded_size;
}
}
result += ')';
return result;
} }
} // namespace caf } // namespace caf
...@@ -27,10 +27,10 @@ std::string to_string(type_id_list xs) { ...@@ -27,10 +27,10 @@ std::string to_string(type_id_list xs) {
return "[]"; return "[]";
std::string result; std::string result;
result += '['; result += '[';
result += detail::global_meta_object(xs[0]).type_name; result += detail::global_meta_object(xs[0])->type_name;
for (size_t index = 1; index < xs.size(); ++index) { for (size_t index = 1; index < xs.size(); ++index) {
result += ", "; result += ", ";
result += detail::global_meta_object(xs[index]).type_name; result += detail::global_meta_object(xs[index])->type_name;
} }
result += ']'; result += ']';
return result; return result;
......
...@@ -160,7 +160,7 @@ CAF_TEST(resizing the global meta objects keeps entries) { ...@@ -160,7 +160,7 @@ CAF_TEST(resizing the global meta objects keeps entries) {
CAF_CHECK_EQUAL(xs2.size(), 2u); CAF_CHECK_EQUAL(xs2.size(), 2u);
CAF_CHECK(eq(xs2[0], meta_i32)); CAF_CHECK(eq(xs2[0], meta_i32));
resize_global_meta_objects(3); resize_global_meta_objects(3);
CAF_CHECK(eq(global_meta_object(0), meta_i32)); CAF_CHECK(eq(*global_meta_object(0), meta_i32));
} }
CAF_TEST(init_global_meta_objects takes care of creating a meta object table) { CAF_TEST(init_global_meta_objects takes care of creating a meta object table) {
...@@ -180,11 +180,11 @@ CAF_TEST(init_global_meta_objects takes care of creating a meta object table) { ...@@ -180,11 +180,11 @@ CAF_TEST(init_global_meta_objects takes care of creating a meta object table) {
}; };
CAF_CHECK(std::equal(xs.begin(), xs.end(), ys.begin(), ys.end(), same)); CAF_CHECK(std::equal(xs.begin(), xs.end(), ys.begin(), ys.end(), same));
CAF_MESSAGE("init_global_meta_objects can initialize allocated chunks"); CAF_MESSAGE("init_global_meta_objects can initialize allocated chunks");
CAF_CHECK_EQUAL(global_meta_object(type_id_v<float>).type_name, nullptr); CAF_CHECK_EQUAL(global_meta_object(type_id_v<float>)->type_name, nullptr);
init_global_meta_objects<builtin_type_ids>(); init_global_meta_objects<builtin_type_ids>();
CAF_MESSAGE("again, calling init_global_meta_objects again is a no-op"); CAF_MESSAGE("again, calling init_global_meta_objects again is a no-op");
init_global_meta_objects<builtin_type_ids>(); init_global_meta_objects<builtin_type_ids>();
CAF_CHECK_EQUAL(global_meta_object(type_id_v<float>).type_name, "float"s); CAF_CHECK_EQUAL(global_meta_object(type_id_v<float>)->type_name, "float"s);
} }
CAF_TEST_FIXTURE_SCOPE_END() CAF_TEST_FIXTURE_SCOPE_END()
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "caf/init_global_meta_objects.hpp" #include "caf/init_global_meta_objects.hpp"
#include "caf/message_handler.hpp" #include "caf/message_handler.hpp"
#include "caf/type_id.hpp" #include "caf/type_id.hpp"
#include "caf/type_id_list.hpp"
namespace { namespace {
...@@ -118,6 +119,17 @@ struct config : actor_system_config { ...@@ -118,6 +119,17 @@ struct config : actor_system_config {
CAF_TEST_FIXTURE_SCOPE(message_tests, test_coordinator_fixture<config>) CAF_TEST_FIXTURE_SCOPE(message_tests, test_coordinator_fixture<config>)
CAF_TEST(messages allow index-based access) {
auto msg = make_message("abc", uint32_t{10}, 20.0);
CAF_CHECK_EQUAL(msg.size(), 3u);
CAF_CHECK_EQUAL(msg.types(),
(make_type_id_list<std::string, uint32_t, double>()));
CAF_CHECK_EQUAL(msg.get_as<std::string>(0), "abc");
CAF_CHECK_EQUAL(msg.get_as<uint32_t>(1), 10u);
CAF_CHECK_EQUAL(msg.get_as<double>(2), 20.0);
CAF_CHECK_EQUAL(msg.cdata().get_reference_count(), 1u);
}
CAF_TEST(compare_custom_types) { CAF_TEST(compare_custom_types) {
s2 tmp; s2 tmp;
tmp.value[0][1] = 100; tmp.value[0][1] = 100;
...@@ -127,15 +139,22 @@ CAF_TEST(compare_custom_types) { ...@@ -127,15 +139,22 @@ CAF_TEST(compare_custom_types) {
CAF_TEST(empty_to_string) { CAF_TEST(empty_to_string) {
message msg; message msg;
CAF_CHECK(to_string(msg), "<empty-message>"); CAF_CHECK_EQUAL(to_string(msg), "<empty-message>");
} }
CAF_TEST(integers_to_string) { CAF_TEST(integers_to_string) {
using ivec = vector<int>; using ivec = vector<int32_t>;
CAF_CHECK_EQUAL(msg_as_string(1, 2, 3), "(1, 2, 3)"); CAF_CHECK_EQUAL(msg_as_string(1, 2, 3), "(1, 2, 3)");
CAF_CHECK_EQUAL(msg_as_string(ivec{1, 2, 3}), "([1, 2, 3])"); CAF_CHECK_EQUAL(msg_as_string(ivec{1, 2, 3}), "([1, 2, 3])");
CAF_CHECK_EQUAL(msg_as_string(ivec{1, 2}, 3, 4, ivec{5, 6, 7}), CAF_CHECK_EQUAL(msg_as_string(ivec{1, 2}, 3, 4, ivec{5, 6, 7}),
"([1, 2], 3, 4, [5, 6, 7])"); "([1, 2], 3, 4, [5, 6, 7])");
auto msg = make_message(ivec{1, 2, 3});
CAF_MESSAGE("s1: " << type_id_v<s1>);
CAF_MESSAGE("ivec: " << type_id_v<ivec>);
CAF_MESSAGE("msg.types: " << msg.types());
CAF_MESSAGE("types #1: " << make_type_id_list<s1>());
CAF_MESSAGE("types #2: " << make_type_id_list<ivec>());
CAF_CHECK_EQUAL(msg.get_as<ivec>(0), ivec({1, 2, 3}));
} }
CAF_TEST(strings_to_string) { CAF_TEST(strings_to_string) {
......
...@@ -187,29 +187,40 @@ Adding Custom Message Types ...@@ -187,29 +187,40 @@ Adding Custom Message Types
--------------------------- ---------------------------
CAF requires serialization support for all of its message types (see CAF requires serialization support for all of its message types (see
:ref:`type-inspection`). However, CAF also needs a mapping of unique type names :ref:`type-inspection`). However, CAF also needs a mapping of unique type IDs to
to user-defined types at runtime. This is required to deserialize arbitrary user-defined types at runtime. This is required to deserialize arbitrary
messages from the network. messages from the network.
As an introductory example, we (again) use the following POD type The type IDs are assigned by listing all custom types in a *type ID block*. CAF
``foo``. assigns ascending IDs to each type by in the block as well as storing the type
name. In the following example, we forward-declare the types ``foo`` and
``foo2`` and register them to CAF in a *type ID block*. The name of the type ID
block is arbitrary, but it must be a valid C++ identifier.
.. literalinclude:: /examples/custom_type/custom_types_1.cpp .. literalinclude:: /examples/custom_type/custom_types_1.cpp
:language: C++ :language: C++
:lines: 24-27 :start-after: --(rst-type-id-block-begin)--
:end-before: --(rst-type-id-block-end)--
To make ``foo`` serializable, we make it inspectable: Aside from a type ID, CAF also requires an ``inspect`` overload in order to be
able to serialize objects. As an introductory example, we (again) use the
following POD type ``foo``.
.. literalinclude:: /examples/custom_type/custom_types_1.cpp .. literalinclude:: /examples/custom_type/custom_types_1.cpp
:language: C++ :language: C++
:lines: 30-34 :start-after: --(rst-foo-begin)--
:end-before: --(rst-foo-end)--
Finally, we give ``foo`` a platform-neutral name and add it to the list By assigning type IDs and providing ``inspect`` overloads, we provide static and
of serializable types by using a custom config class. 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 .. literalinclude:: /examples/custom_type/custom_types_1.cpp
:language: C++ :language: C++
:lines: 75-78,81-84 :start-after: --(rst-config-begin)--
:end-before: --(rst-config-end)--
Adding Custom Error Types Adding Custom Error Types
------------------------- -------------------------
...@@ -231,18 +242,14 @@ simple ``calculator`` actor. ...@@ -231,18 +242,14 @@ simple ``calculator`` actor.
.. literalinclude:: /examples/remoting/remote_spawn.cpp .. literalinclude:: /examples/remoting/remote_spawn.cpp
:language: C++ :language: C++
:lines: 33-34 :start-after: --(rst-calculator-begin)--
:end-before: --(rst-calculator-end)--
Adding the calculator actor type to our config is achieved by calling Adding the calculator actor type to our config is achieved by calling
``add_actor_type<T>``. Note that adding an actor type in this way ``add_actor_type``. After calling this in our config, we can spawn the
implicitly calls ``add_message_type<T>`` for typed actors ``calculator`` anywhere in the distributed actor system (assuming all nodes use
add-custom-message-type_. This makes our ``calculator`` actor type the same config). Note that the handle type still requires a type ID (see
serializable and also enables remote nodes to spawn calculators anywhere in the add-custom-message-type_).
distributed actor system (assuming all nodes use the same config).
.. literalinclude:: /examples/remoting/remote_spawn.cpp
:language: C++
:lines: 98-109
Our final example illustrates how to spawn a ``calculator`` locally by Our final example illustrates how to spawn a ``calculator`` locally by
using its type name. Because the dynamic type name lookup can fail and the using its type name. Because the dynamic type name lookup can fail and the
......
...@@ -10,7 +10,8 @@ named "calculator". ...@@ -10,7 +10,8 @@ named "calculator".
.. literalinclude:: /examples/remoting/remote_spawn.cpp .. literalinclude:: /examples/remoting/remote_spawn.cpp
:language: C++ :language: C++
:lines: 123-137 :start-after: --(rst-client-begin)--
:end-before: --(rst-client-end)--
We first connect to a CAF node with ``middleman().connect(...)``. On success, We first connect to a CAF node with ``middleman().connect(...)``. On success,
``connect`` returns the node ID we need for ``remote_spawn``. This requires the ``connect`` returns the node ID we need for ``remote_spawn``. This requires the
......
...@@ -69,7 +69,8 @@ Defining Sources ...@@ -69,7 +69,8 @@ Defining Sources
.. literalinclude:: /examples/streaming/integer_stream.cpp .. literalinclude:: /examples/streaming/integer_stream.cpp
:language: C++ :language: C++
:lines: 17-48 :start-after: --(rst-source-begin)--
:end-before: --(rst-source-end)--
The simplest way to defining a source is to use the The simplest way to defining a source is to use the
``attach_stream_source`` function and pass it four arguments: a pointer ``attach_stream_source`` function and pass it four arguments: a pointer
...@@ -81,7 +82,8 @@ Defining Stages ...@@ -81,7 +82,8 @@ Defining Stages
.. literalinclude:: /examples/streaming/integer_stream.cpp .. literalinclude:: /examples/streaming/integer_stream.cpp
:language: C++ :language: C++
:lines: 50-83 :start-after: --(rst-stage-begin)--
:end-before: --(rst-stage-end)--
The function ``make_stage`` also takes three lambdas but additionally The function ``make_stage`` also takes three lambdas but additionally
the received input stream handshake as first argument. Instead of a predicate, the received input stream handshake as first argument. Instead of a predicate,
...@@ -93,7 +95,8 @@ Defining Sinks ...@@ -93,7 +95,8 @@ Defining Sinks
.. literalinclude:: /examples/streaming/integer_stream.cpp .. literalinclude:: /examples/streaming/integer_stream.cpp
:language: C++ :language: C++
:lines: 85-114 :start-after: --(rst-sink-begin)--
:end-before: --(rst-sink-end)--
The function ``make_sink`` is similar to ``make_stage``, except The function ``make_sink`` is similar to ``make_stage``, except
that is does not produce outputs. that is does not produce outputs.
...@@ -103,7 +106,8 @@ Initiating Streams ...@@ -103,7 +106,8 @@ Initiating Streams
.. literalinclude:: /examples/streaming/integer_stream.cpp .. literalinclude:: /examples/streaming/integer_stream.cpp
:language: C++ :language: C++
:lines: 128-132 :start-after: --(rst-main-begin)--
:end-before: --(rst-main-end)--
In our example, we always have a source ``int_source`` and a sink In our example, we always have a source ``int_source`` and a sink
``int_sink`` with an optional stage ``int_selector``. Sending ``int_sink`` with an optional stage ``int_selector``. Sending
......
...@@ -49,10 +49,9 @@ implementing a hash function. ...@@ -49,10 +49,9 @@ implementing a hash function.
Inspector { Inspector {
using result_type = T; using result_type = T;
if (inspector only requires read access to the state of T) static constexpr bool reads_state = ...;
static constexpr bool reads_state = true;
else static constexpr bool writes_state = ...;
static constexpr bool writes_state = true;
template <class... Ts> template <class... Ts>
result_type operator()(Ts&&...); result_type operator()(Ts&&...);
...@@ -116,7 +115,8 @@ access to its members. ...@@ -116,7 +115,8 @@ access to its members.
.. literalinclude:: /examples/custom_type/custom_types_3.cpp .. literalinclude:: /examples/custom_type/custom_types_3.cpp
:language: C++ :language: C++
:lines: 20-49 :start-after: --(rst-foo-begin)--
:end-before: --(rst-foo-end)--
Since there is no access to the data fields ``a_`` and ``b_`` Since there is no access to the data fields ``a_`` and ``b_``
(and assuming no changes to ``foo`` are possible), we need to split our (and assuming no changes to ``foo`` are possible), we need to split our
...@@ -124,7 +124,8 @@ implementation of ``inspect`` as shown below. ...@@ -124,7 +124,8 @@ implementation of ``inspect`` as shown below.
.. literalinclude:: /examples/custom_type/custom_types_3.cpp .. literalinclude:: /examples/custom_type/custom_types_3.cpp
:language: C++ :language: C++
:lines: 76-103 :start-after: --(rst-inspect-begin)--
:end-before: --(rst-inspect-end)--
The purpose of the scope guard in the example above is to write the content of The purpose of the scope guard in the example above is to write the content of
the temporaries back to ``foo`` at scope exit automatically. Storing the temporaries back to ``foo`` at scope exit automatically. Storing
......
...@@ -8,6 +8,17 @@ ...@@ -8,6 +8,17 @@
#include "caf/all.hpp" #include "caf/all.hpp"
struct entity;
struct se_event;
CAF_BEGIN_TYPE_ID_BLOCK(caf_vec, first_custom_type_id)
CAF_ADD_TYPE_ID(caf_vec, entity);
CAF_ADD_TYPE_ID(caf_vec, se_event);
CAF_END_TYPE_ID_BLOCK(caf_vec)
using std::string; using std::string;
using namespace caf; using namespace caf;
...@@ -739,6 +750,7 @@ struct config : public actor_system_config { ...@@ -739,6 +750,7 @@ struct config : public actor_system_config {
bool include_hidden_actors = false; bool include_hidden_actors = false;
size_t verbosity = 0; size_t verbosity = 0;
config() { config() {
init_global_meta_objects<caf_vec_type_ids>();
opt_group{custom_options_, "global"} opt_group{custom_options_, "global"}
.add(output_file, "output-file,o", "Path for the output file") .add(output_file, "output-file,o", "Path for the output file")
.add(include_hidden_actors, "include-hidden-actors,i", .add(include_hidden_actors, "include-hidden-actors,i",
......
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