Unverified Commit 13fc58a2 authored by Joseph Noir's avatar Joseph Noir Committed by GitHub

Merge pull request #1007

Replace custom atom type with tag types
parents 93f6d712 f0f3f394
...@@ -36,9 +36,9 @@ MacroBlockBegin: "^BEGIN_STATE$" ...@@ -36,9 +36,9 @@ MacroBlockBegin: "^BEGIN_STATE$"
MacroBlockEnd: "^END_STATE$" MacroBlockEnd: "^END_STATE$"
MaxEmptyLinesToKeep: 1 MaxEmptyLinesToKeep: 1
NamespaceIndentation: None NamespaceIndentation: None
PenaltyBreakAssignment: 10 PenaltyBreakAssignment: 25
PenaltyBreakBeforeFirstCallParameter: 30 PenaltyBreakBeforeFirstCallParameter: 30
PenaltyReturnTypeOnItsOwnLine: 5 PenaltyReturnTypeOnItsOwnLine: 25
PointerAlignment: Left PointerAlignment: Left
ReflowComments: true ReflowComments: true
SortIncludes: true SortIncludes: true
......
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
#include "caf/actor_system_config.hpp" #include "caf/actor_system_config.hpp"
#include "caf/config.hpp" #include "caf/config.hpp"
#include "caf/detail/parser/chars.hpp" #include "caf/detail/parser/chars.hpp"
#include "caf/detail/parser/read_atom.hpp"
#include "caf/detail/parser/read_bool.hpp" #include "caf/detail/parser/read_bool.hpp"
#include "caf/detail/parser/read_number_or_timespan.hpp" #include "caf/detail/parser/read_number_or_timespan.hpp"
#include "caf/detail/parser/read_string.hpp" #include "caf/detail/parser/read_string.hpp"
......
...@@ -227,7 +227,7 @@ be overloaded only by their return type, interfaces cannot accept one input ...@@ -227,7 +227,7 @@ be overloaded only by their return type, interfaces cannot accept one input
twice (possibly mapping it to different outputs). The example below defines a twice (possibly mapping it to different outputs). The example below defines a
messaging interface for a simple calculator. messaging interface for a simple calculator.
\cppexample[17-21]{message_passing/calculator} \cppexample[17-18]{message_passing/calculator}
It is not required to create a type alias such as \lstinline^calculator_actor^, It is not required to create a type alias such as \lstinline^calculator_actor^,
but it makes dealing with statically typed actors much easier. Also, a central but it makes dealing with statically typed actors much easier. Also, a central
...@@ -277,11 +277,11 @@ Both statically and dynamically typed actors are spawned from an ...@@ -277,11 +277,11 @@ Both statically and dynamically typed actors are spawned from an
function either takes a function as first argument or a class as first template function either takes a function as first argument or a class as first template
parameter. For example, the following functions and classes represent actors. parameter. For example, the following functions and classes represent actors.
\cppexample[24-29]{message_passing/calculator} \cppexample[21-26]{message_passing/calculator}
Spawning an actor for each implementation is illustrated below. Spawning an actor for each implementation is illustrated below.
\cppexample[140-145]{message_passing/calculator} \cppexample[123-128]{message_passing/calculator}
Additional arguments to \lstinline^spawn^ are passed to the constructor of a Additional arguments to \lstinline^spawn^ are passed to the constructor of a
class or used as additional function arguments, respectively. In the example class or used as additional function arguments, respectively. In the example
...@@ -317,7 +317,7 @@ and illustrate one blocking actor and two event-based actors (statically and ...@@ -317,7 +317,7 @@ and illustrate one blocking actor and two event-based actors (statically and
dynamically typed). dynamically typed).
\clearpage \clearpage
\cppexample[31-72]{message_passing/calculator} \cppexample[28-56]{message_passing/calculator}
\clearpage \clearpage
\subsection{Class-based Actors} \subsection{Class-based Actors}
...@@ -343,7 +343,7 @@ behaviors~\see{composable-behavior} that works well with inheritance. The ...@@ -343,7 +343,7 @@ behaviors~\see{composable-behavior} that works well with inheritance. The
following three examples implement the forward declarations shown in following three examples implement the forward declarations shown in
\sref{spawn}. \sref{spawn}.
\cppexample[74-108]{message_passing/calculator} \cppexample[58-92]{message_passing/calculator}
\clearpage \clearpage
\subsection{Stateful Actors} \subsection{Stateful Actors}
...@@ -405,7 +405,7 @@ Any composable (or composed) behavior with no pure virtual member functions can ...@@ -405,7 +405,7 @@ Any composable (or composed) behavior with no pure virtual member functions can
be spawned directly through an actor system by calling be spawned directly through an actor system by calling
\lstinline^system.spawn<...>()^, as shown below. \lstinline^system.spawn<...>()^, as shown below.
\cppexample[20-52]{composition/calculator_behavior} \cppexample[20-45]{composition/calculator_behavior}
\clearpage \clearpage
...@@ -435,7 +435,7 @@ the actor has already exited. Otherwise, the actor will execute it as part of ...@@ -435,7 +435,7 @@ the actor has already exited. Otherwise, the actor will execute it as part of
its termination. The following example attaches a function object to actors for its termination. The following example attaches a function object to actors for
printing a custom string on exit. printing a custom string on exit.
\cppexample[46-50]{broker/simple_broker} \cppexample[42-47]{broker/simple_broker}
It is possible to attach code to remote actors. However, the cleanup code will It is possible to attach code to remote actors. However, the cleanup code will
run on the local machine. run on the local machine.
......
...@@ -110,7 +110,7 @@ hard-coded defaults. Users can add any number of custom program options by ...@@ -110,7 +110,7 @@ hard-coded defaults. Users can add any number of custom program options by
implementing a subtype of \lstinline^actor_system_config^. The example below implementing a subtype of \lstinline^actor_system_config^. The example below
adds three options to the \lstinline^global^ category. adds three options to the \lstinline^global^ category.
\cppexample[222-234]{remoting/distributed_calculator} \cppexample[206-218]{remoting/distributed_calculator}
We create a new \lstinline^global^ category in \lstinline^custom_options_}^. We create a new \lstinline^global^ category in \lstinline^custom_options_}^.
Each following call to \lstinline^add^ then appends individual options to the Each following call to \lstinline^add^ then appends individual options to the
...@@ -207,7 +207,7 @@ name. In particular, this enables spawning of actors on a different node ...@@ -207,7 +207,7 @@ name. In particular, this enables spawning of actors on a different node
\see{remote-spawn}. For our example configuration, we consider the following \see{remote-spawn}. For our example configuration, we consider the following
simple \lstinline^calculator^ actor. simple \lstinline^calculator^ actor.
\cppexample[33-39]{remoting/remote_spawn} \cppexample[33-34]{remoting/remote_spawn}
Adding the calculator actor type to our config is achieved by calling Adding the calculator actor type to our config is achieved by calling
\lstinline^add_actor_type<T>^. Note that adding an actor type in this way \lstinline^add_actor_type<T>^. Note that adding an actor type in this way
...@@ -216,7 +216,7 @@ implicitly calls \lstinline^add_message_type<T>^ for typed actors ...@@ -216,7 +216,7 @@ implicitly calls \lstinline^add_message_type<T>^ for typed actors
serializable and also enables remote nodes to spawn calculators anywhere in the serializable and also enables remote nodes to spawn calculators anywhere in the
distributed actor system (assuming all nodes use the same config). distributed actor system (assuming all nodes use the same config).
\cppexample[99-101,106-106,110-101]{remoting/remote_spawn} \cppexample[98-109]{remoting/remote_spawn}
Our final example illustrates how to spawn a \lstinline^calculator^ locally by Our final example illustrates how to spawn a \lstinline^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
......
...@@ -37,30 +37,12 @@ provide additional context information. ...@@ -37,30 +37,12 @@ provide additional context information.
\label{custom-error} \label{custom-error}
Adding custom error categories requires three steps: (1)~declare an enum class Adding custom error categories requires three steps: (1)~declare an enum class
of type \lstinline^uint8_t^ with the first value starting at 1, (2)~implement a of type \lstinline^uint8_t^ with the first value starting at 1, (2)~specialize
free function \lstinline^make_error^ that converts the enum to an \lstinline^error_category^ to give your type a custom ID (value 0-99 are
\lstinline^error^ object, (3)~add the custom category to the actor system with reserved by CAF), and (3)~add your error category to the actor system config.
a render function. The last step is optional to allow users to retrieve a The following example adds custom error codes for math errors.
better string representation from \lstinline^system.render(x)^ than
\lstinline^to_string(x)^ can offer. Note that any error code with value 0 is
interpreted as \emph{not-an-error}. The following example adds a custom error
category by performing the first two steps.
\cppexample[19-34]{message_passing/divider} \cppexample[17-47]{message_passing/divider}
The implementation of \lstinline^to_string(error)^ is unable to call string
conversions for custom error categories. Hence,
\lstinline^to_string(make_error(math_error::division_by_zero))^ returns
\lstinline^"error(1, math)"^.
The following code adds a rendering function to the actor system to provide a
more satisfactory string conversion.
\cppexample[50-58]{message_passing/divider}
With the custom rendering function,
\lstinline^system.render(make_error(math_error::division_by_zero))^ returns
\lstinline^"math_error(division_by_zero)"^.
\clearpage \clearpage
\subsection{System Error Codes} \subsection{System Error Codes}
......
...@@ -221,12 +221,12 @@ as a fallback in scheduled actors. ...@@ -221,12 +221,12 @@ as a fallback in scheduled actors.
As an example, we consider a simple divider that returns an error on a division As an example, we consider a simple divider that returns an error on a division
by zero. This examples uses a custom error category~\see{error}. by zero. This examples uses a custom error category~\see{error}.
\cppexample[19-25,35-48]{message_passing/divider} \cppexample[17-19,49-59]{message_passing/divider}
When sending requests to the divider, we use a custom error handlers to report When sending requests to the divider, we use a custom error handlers to report
errors to the user. errors to the user.
\cppexample[68-77]{message_passing/divider} \cppexample[70-76]{message_passing/divider}
\clearpage \clearpage
\subsection{Delaying Messages} \subsection{Delaying Messages}
...@@ -235,7 +235,7 @@ errors to the user. ...@@ -235,7 +235,7 @@ errors to the user.
Messages can be delayed by using the function \lstinline^delayed_send^, as Messages can be delayed by using the function \lstinline^delayed_send^, as
illustrated in the following time-based loop example. illustrated in the following time-based loop example.
\cppexample[56-75]{message_passing/dancing_kirby} \cppexample[58-75]{message_passing/dancing_kirby}
\clearpage \clearpage
\subsection{Delegating Messages} \subsection{Delegating Messages}
...@@ -272,7 +272,7 @@ Returning the result of \lstinline^delegate(...)^ from a message handler, as ...@@ -272,7 +272,7 @@ Returning the result of \lstinline^delegate(...)^ from a message handler, as
shown in the example below, suppresses the implicit response message and allows shown in the example below, suppresses the implicit response message and allows
the compiler to check the result type when using statically typed actors. the compiler to check the result type when using statically typed actors.
\cppexample[15-42]{message_passing/delegating} \cppexample[15-36]{message_passing/delegating}
\subsection{Response Promises} \subsection{Response Promises}
\label{promise} \label{promise}
......
...@@ -6,7 +6,7 @@ Remote spawning is an extension of the dynamic spawn using run-time type names ...@@ -6,7 +6,7 @@ Remote spawning is an extension of the dynamic spawn using run-time type names
named \lstinline^calculator^ with an actor implementing this messaging named \lstinline^calculator^ with an actor implementing this messaging
interface named "calculator". interface named "calculator".
\cppexample[125-143]{remoting/remote_spawn} \cppexample[123-137]{remoting/remote_spawn}
We first connect to a CAF node with \lstinline^middleman().connect(...)^. On We first connect to a CAF node with \lstinline^middleman().connect(...)^. On
success, \lstinline^connect^ returns the node ID we need for success, \lstinline^connect^ returns the node ID we need for
......
...@@ -56,7 +56,7 @@ data to the next available worker. ...@@ -56,7 +56,7 @@ data to the next available worker.
\subsection{Defining Sources} \subsection{Defining Sources}
\cppexample[17-46]{streaming/integer_stream} \cppexample[17-48]{streaming/integer_stream}
The simplest way to defining a source is to use the The simplest way to defining a source is to use the
\lstinline^attach_stream_source^ function and pass it four arguments: a pointer \lstinline^attach_stream_source^ function and pass it four arguments: a pointer
...@@ -67,7 +67,7 @@ producing values, and \emph{predicate} for signaling the end of the stream. ...@@ -67,7 +67,7 @@ producing values, and \emph{predicate} for signaling the end of the stream.
\subsection{Defining Stages} \subsection{Defining Stages}
\cppexample[48-78]{streaming/integer_stream} \cppexample[50-83]{streaming/integer_stream}
The function \lstinline^make_stage^ also takes three lambdas but additionally The function \lstinline^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,
...@@ -78,7 +78,7 @@ data on its own and a stream terminates if no more sources exist. ...@@ -78,7 +78,7 @@ data on its own and a stream terminates if no more sources exist.
\subsection{Defining Sinks} \subsection{Defining Sinks}
\cppexample[80-106]{streaming/integer_stream} \cppexample[85-114]{streaming/integer_stream}
The function \lstinline^make_sink^ is similar to \lstinline^make_stage^, except The function \lstinline^make_sink^ is similar to \lstinline^make_stage^, except
that is does not produce outputs. that is does not produce outputs.
...@@ -87,7 +87,7 @@ that is does not produce outputs. ...@@ -87,7 +87,7 @@ that is does not produce outputs.
\subsection{Initiating Streams} \subsection{Initiating Streams}
\cppexample[121-125]{streaming/integer_stream} \cppexample[128-132]{streaming/integer_stream}
In our example, we always have a source \lstinline^int_source^ and a sink In our example, we always have a source \lstinline^int_source^ and a sink
\lstinline^int_sink^ with an optional stage \lstinline^int_selector^. Sending \lstinline^int_sink^ with an optional stage \lstinline^int_selector^. Sending
......
...@@ -170,4 +170,4 @@ The following example implements two actors, \lstinline^ping^ and ...@@ -170,4 +170,4 @@ The following example implements two actors, \lstinline^ping^ and
\lstinline^expect^ and verifies that no additional messages exist using \lstinline^expect^ and verifies that no additional messages exist using
\lstinline^disallow^. \lstinline^disallow^.
\cppexample[12-65]{testing/ping_pong} \cppexample[12-60]{testing/ping_pong}
...@@ -5,32 +5,33 @@ ...@@ -5,32 +5,33 @@
* Minimal setup: * * Minimal setup: *
* - ./build/bin/broker -s 4242 * * - ./build/bin/broker -s 4242 *
* - ./build/bin/broker -c localhost 4242 * * - ./build/bin/broker -c localhost 4242 *
\ ******************************************************************************/ \
******************************************************************************/
// Manual refs: 46-50 (Actors.tex) // Manual refs: 42-47 (Actors.tex)
#include "caf/config.hpp" #include "caf/config.hpp"
#ifdef WIN32 #ifdef WIN32
# define _WIN32_WINNT 0x0600 # define _WIN32_WINNT 0x0600
# include <winsock2.h> # include <winsock2.h>
#else #else
# include <arpa/inet.h> // htonl # include <arpa/inet.h> // htonl
#endif #endif
#include <vector>
#include <string>
#include <limits>
#include <memory>
#include <cstdint>
#include <cassert> #include <cassert>
#include <cstdint>
#include <iostream> #include <iostream>
#include <limits>
#include <memory>
#include <string>
#include <vector>
#include "caf/all.hpp" #include "caf/all.hpp"
#include "caf/io/all.hpp" #include "caf/io/all.hpp"
using std::cout;
using std::cerr; using std::cerr;
using std::cout;
using std::endl; using std::endl;
using namespace caf; using namespace caf;
...@@ -38,41 +39,41 @@ using namespace caf::io; ...@@ -38,41 +39,41 @@ using namespace caf::io;
namespace { namespace {
using ping_atom = atom_constant<atom("ping")>; // Utility function to print an exit message with custom name.
using pong_atom = atom_constant<atom("pong")>;
using kickoff_atom = atom_constant<atom("kickoff")>;
// utility function to print an exit message with custom name
void print_on_exit(const actor& hdl, const std::string& name) { void print_on_exit(const actor& hdl, const std::string& name) {
hdl->attach_functor([=](const error& reason) { hdl->attach_functor([=](const error& reason) {
cout << name << " exited: " << to_string(reason) << endl; cout << name << " exited: " << to_string(reason) << endl;
}); });
} }
enum class op : uint8_t {
ping,
pong,
};
behavior ping(event_based_actor* self, size_t num_pings) { behavior ping(event_based_actor* self, size_t num_pings) {
auto count = std::make_shared<size_t>(0); auto count = std::make_shared<size_t>(0);
return { return {
[=](kickoff_atom, const actor& pong) { [=](ok_atom, const actor& pong) {
self->send(pong, ping_atom::value, int32_t(1)); self->send(pong, ping_atom_v, int32_t(1));
self->become ( self->become([=](pong_atom, int32_t value) -> result<ping_atom, int32_t> {
[=](pong_atom, int32_t value) -> result<ping_atom, int32_t> { if (++*count >= num_pings)
if (++*count >= num_pings) self->quit(); self->quit();
return {ping_atom::value, value + 1}; return {ping_atom_v, value + 1};
} });
); },
}
}; };
} }
behavior pong() { behavior pong() {
return { return {
[](ping_atom, int32_t value) -> result<pong_atom, int32_t> { [](ping_atom, int32_t value) -> result<pong_atom, int32_t> {
return {pong_atom::value, value}; return {pong_atom_v, value};
} },
}; };
} }
// utility function for sending an integer type // Utility function for sending an integer type.
template <class T> template <class T>
void write_int(broker* self, connection_handle hdl, T value) { void write_int(broker* self, connection_handle hdl, T value) {
using unsigned_type = typename std::make_unsigned<T>::type; using unsigned_type = typename std::make_unsigned<T>::type;
...@@ -81,13 +82,7 @@ void write_int(broker* self, connection_handle hdl, T value) { ...@@ -81,13 +82,7 @@ void write_int(broker* self, connection_handle hdl, T value) {
self->flush(hdl); self->flush(hdl);
} }
void write_int(broker* self, connection_handle hdl, uint64_t value) { // Utility function for reading an ingeger from incoming data.
// write two uint32 values instead (htonl does not work for 64bit integers)
write_int(self, hdl, static_cast<uint32_t>(value));
write_int(self, hdl, static_cast<uint32_t>(value >> sizeof(uint32_t)));
}
// utility function for reading an ingeger from incoming data
template <class T> template <class T>
void read_int(const void* data, T& storage) { void read_int(const void* data, T& storage) {
using unsigned_type = typename std::make_unsigned<T>::type; using unsigned_type = typename std::make_unsigned<T>::type;
...@@ -95,38 +90,30 @@ void read_int(const void* data, T& storage) { ...@@ -95,38 +90,30 @@ void read_int(const void* data, T& storage) {
storage = static_cast<T>(ntohl(static_cast<unsigned_type>(storage))); storage = static_cast<T>(ntohl(static_cast<unsigned_type>(storage)));
} }
void read_int(const void* data, uint64_t& storage) { // Implementation of our broker.
uint32_t first;
uint32_t second;
read_int(data, first);
read_int(reinterpret_cast<const char*>(data) + sizeof(uint32_t), second);
storage = first | (static_cast<uint64_t>(second) << sizeof(uint32_t));
}
// implementation of our broker
behavior broker_impl(broker* self, connection_handle hdl, const actor& buddy) { behavior broker_impl(broker* self, connection_handle hdl, const actor& buddy) {
// we assume io_fsm manages a broker with exactly one connection, // We assume io_fsm manages a broker with exactly one connection,
// i.e., the connection ponted to by `hdl` // i.e., the connection ponted to by `hdl`.
assert(self->num_connections() == 1); assert(self->num_connections() == 1);
// monitor buddy to quit broker if buddy is done // Monitor buddy to quit broker if buddy is done.
self->monitor(buddy); self->monitor(buddy);
self->set_down_handler([=](down_msg& dm) { self->set_down_handler([=](down_msg& dm) {
if (dm.source == buddy) { if (dm.source == buddy) {
aout(self) << "our buddy is down" << endl; aout(self) << "our buddy is down" << endl;
// quit for same reason // Quit for same reason.
self->quit(dm.reason); self->quit(dm.reason);
} }
}); });
// setup: we are exchanging only messages consisting of an atom // Setup: we are exchanging only messages consisting of an atom
// (as uint64_t) and an integer value (int32_t) // (as uint64_t) and an integer value (int32_t).
self->configure_read(hdl, receive_policy::exactly(sizeof(uint64_t) + self->configure_read(
sizeof(int32_t))); hdl, receive_policy::exactly(sizeof(uint64_t) + sizeof(int32_t)));
// our message handlers // Our message handlers.
return { return {
[=](const connection_closed_msg& msg) { [=](const connection_closed_msg& msg) {
// brokers can multiplex any number of connections, however // Brokers can multiplex any number of connections, however
// this example assumes io_fsm to manage a broker with // this example assumes io_fsm to manage a broker with
// exactly one connection // exactly one connection.
if (msg.handle == hdl) { if (msg.handle == hdl) {
aout(self) << "connection closed" << endl; aout(self) << "connection closed" << endl;
// force buddy to quit // force buddy to quit
...@@ -134,29 +121,39 @@ behavior broker_impl(broker* self, connection_handle hdl, const actor& buddy) { ...@@ -134,29 +121,39 @@ behavior broker_impl(broker* self, connection_handle hdl, const actor& buddy) {
self->quit(exit_reason::remote_link_unreachable); self->quit(exit_reason::remote_link_unreachable);
} }
}, },
[=](atom_value av, int32_t i) { [=](ping_atom, int32_t i) {
assert(av == ping_atom::value || av == pong_atom::value); aout(self) << "send {ping, " << i << "}" << endl;
aout(self) << "send {" << to_string(av) << ", " << i << "}" << endl; write_int(self, hdl, static_cast<uint8_t>(op::ping));
// cast atom to its underlying type, i.e., uint64_t write_int(self, hdl, i);
write_int(self, hdl, static_cast<uint64_t>(av)); },
[=](pong_atom, int32_t i) {
aout(self) << "send {pong, " << i << "}" << endl;
write_int(self, hdl, static_cast<uint8_t>(op::pong));
write_int(self, hdl, i); write_int(self, hdl, i);
}, },
[=](const new_data_msg& msg) { [=](const new_data_msg& msg) {
// read the atom value as uint64_t from buffer // Read the operation value as uint8_t from buffer.
uint64_t atm_val; uint8_t op_val;
read_int(msg.buf.data(), atm_val); read_int(msg.buf.data(), op_val);
// cast to original type // Read integer value from buffer, jumping to the correct
auto atm = static_cast<atom_value>(atm_val); // position via offset_data(...).
// read integer value from buffer, jumping to the correct
// position via offset_data(...)
int32_t ival; int32_t ival;
read_int(msg.buf.data() + sizeof(uint64_t), ival); read_int(msg.buf.data() + sizeof(uint8_t), ival);
// show some output // Show some output.
aout(self) << "received {" << to_string(atm) << ", " << ival << "}" aout(self) << "received {" << op_val << ", " << ival << "}" << endl;
<< endl; // Send composed message to our buddy.
// send composed message to our buddy switch (static_cast<op>(op_val)) {
self->send(buddy, atm, ival); case op::ping:
} self->send(buddy, ping_atom_v, ival);
break;
case op::pong:
self->send(buddy, pong_atom_v, ival);
break;
default:
aout(self) << "invalid value for op_val, stop" << endl;
self->quit(sec::invalid_argument);
}
},
}; };
} }
...@@ -165,13 +162,13 @@ behavior server(broker* self, const actor& buddy) { ...@@ -165,13 +162,13 @@ behavior server(broker* self, const actor& buddy) {
return { return {
[=](const new_connection_msg& msg) { [=](const new_connection_msg& msg) {
aout(self) << "server accepted new connection" << endl; aout(self) << "server accepted new connection" << endl;
// by forking into a new broker, we are no longer // By forking into a new broker, we are no longer
// responsible for the connection // responsible for the connection.
auto impl = self->fork(broker_impl, msg.handle, buddy); auto impl = self->fork(broker_impl, msg.handle, buddy);
print_on_exit(impl, "broker_impl"); print_on_exit(impl, "broker_impl");
aout(self) << "quit server (only accept 1 connection)" << endl; aout(self) << "quit server (only accept 1 connection)" << endl;
self->quit(); self->quit();
} },
}; };
} }
...@@ -183,9 +180,9 @@ public: ...@@ -183,9 +180,9 @@ public:
config() { config() {
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 host (ignored in server mode)") .add(host, "host,H", "set host (ignored in server mode)")
.add(server_mode, "server-mode,s", "enable server mode"); .add(server_mode, "server-mode,s", "enable server mode");
} }
}; };
...@@ -196,7 +193,7 @@ void run_server(actor_system& system, const config& cfg) { ...@@ -196,7 +193,7 @@ void run_server(actor_system& system, const config& cfg) {
pong_actor); pong_actor);
if (!server_actor) { if (!server_actor) {
std::cerr << "failed to spawn server: " std::cerr << "failed to spawn server: "
<< system.render(server_actor.error()) << endl; << system.render(server_actor.error()) << endl;
return; return;
} }
print_on_exit(*server_actor, "server"); print_on_exit(*server_actor, "server");
...@@ -208,13 +205,13 @@ void run_client(actor_system& system, const config& cfg) { ...@@ -208,13 +205,13 @@ void run_client(actor_system& system, const config& cfg) {
auto io_actor = system.middleman().spawn_client(broker_impl, cfg.host, auto io_actor = system.middleman().spawn_client(broker_impl, cfg.host,
cfg.port, ping_actor); cfg.port, ping_actor);
if (!io_actor) { if (!io_actor) {
std::cerr << "failed to spawn client: " std::cerr << "failed to spawn client: " << system.render(io_actor.error())
<< system.render(io_actor.error()) << endl; << endl;
return; return;
} }
print_on_exit(ping_actor, "ping"); print_on_exit(ping_actor, "ping");
print_on_exit(*io_actor, "protobuf_io"); print_on_exit(*io_actor, "protobuf_io");
send_as(*io_actor, ping_actor, kickoff_atom::value, *io_actor); send_as(*io_actor, ping_actor, ok_atom_v, *io_actor);
} }
void caf_main(actor_system& system, const config& cfg) { void caf_main(actor_system& system, const config& cfg) {
......
...@@ -13,8 +13,6 @@ using namespace caf::io; ...@@ -13,8 +13,6 @@ using namespace caf::io;
namespace { namespace {
using tick_atom = atom_constant<atom("tick")>;
constexpr const char http_ok[] = R"__(HTTP/1.1 200 OK constexpr const char http_ok[] = R"__(HTTP/1.1 200 OK
Content-Type: text/plain Content-Type: text/plain
Connection: keep-alive Connection: keep-alive
...@@ -51,7 +49,7 @@ behavior server(broker* self) { ...@@ -51,7 +49,7 @@ behavior server(broker* self) {
self->set_down_handler([=](down_msg&) { self->set_down_handler([=](down_msg&) {
++*counter; ++*counter;
}); });
self->delayed_send(self, std::chrono::seconds(1), tick_atom::value); self->delayed_send(self, std::chrono::seconds(1), tick_atom_v);
return { return {
[=](const new_connection_msg& ncm) { [=](const new_connection_msg& ncm) {
auto worker = self->fork(connection_worker, ncm.handle); auto worker = self->fork(connection_worker, ncm.handle);
...@@ -61,7 +59,7 @@ behavior server(broker* self) { ...@@ -61,7 +59,7 @@ behavior server(broker* self) {
[=](tick_atom) { [=](tick_atom) {
aout(self) << "Finished " << *counter << " requests per second." << endl; aout(self) << "Finished " << *counter << " requests per second." << endl;
*counter = 0; *counter = 0;
self->delayed_send(self, std::chrono::seconds(1), tick_atom::value); self->delayed_send(self, std::chrono::seconds(1), tick_atom_v);
} }
}; };
} }
......
...@@ -17,11 +17,9 @@ using namespace caf; ...@@ -17,11 +17,9 @@ using namespace caf;
namespace { namespace {
// using add_atom = atom_constant<atom("add")>; (defined in atom.hpp)
using multiply_atom = atom_constant<atom("multiply")>;
using adder = typed_actor<replies_to<add_atom, int, int>::with<int>>; using adder = typed_actor<replies_to<add_atom, int, int>::with<int>>;
using multiplier = typed_actor<replies_to<multiply_atom, int, int>::with<int>>;
using multiplier = typed_actor<replies_to<mul_atom, int, int>::with<int>>;
class adder_bhvr : public composable_behavior<adder> { class adder_bhvr : public composable_behavior<adder> {
public: public:
...@@ -32,7 +30,7 @@ public: ...@@ -32,7 +30,7 @@ public:
class multiplier_bhvr : public composable_behavior<multiplier> { class multiplier_bhvr : public composable_behavior<multiplier> {
public: public:
result<int> operator()(multiply_atom, int x, int y) override { result<int> operator()(mul_atom, int x, int y) override {
return x * y; return x * y;
} }
}; };
...@@ -40,12 +38,12 @@ public: ...@@ -40,12 +38,12 @@ public:
// calculator_bhvr can be inherited from or composed further // calculator_bhvr can be inherited from or composed further
using calculator_bhvr = composed_behavior<adder_bhvr, multiplier_bhvr>; using calculator_bhvr = composed_behavior<adder_bhvr, multiplier_bhvr>;
} // namespace
void caf_main(actor_system& system) { void caf_main(actor_system& system) {
auto f = make_function_view(system.spawn<calculator_bhvr>()); auto f = make_function_view(system.spawn<calculator_bhvr>());
cout << "10 + 20 = " << f(add_atom::value, 10, 20) << endl; cout << "10 + 20 = " << f(add_atom_v, 10, 20) << endl;
cout << "7 * 9 = " << f(multiply_atom::value, 7, 9) << endl; cout << "7 * 9 = " << f(mul_atom_v, 7, 9) << endl;
} }
} // namespace
CAF_MAIN() CAF_MAIN()
...@@ -47,8 +47,8 @@ protected: ...@@ -47,8 +47,8 @@ protected:
void caf_main(actor_system& system) { void caf_main(actor_system& system) {
auto f = make_function_view(system.spawn<dict_behavior>()); auto f = make_function_view(system.spawn<dict_behavior>());
f(put_atom::value, "CAF", "success"); f(put_atom_v, "CAF", "success");
cout << "CAF is the key to " << f(get_atom::value, "CAF") << endl; cout << "CAF is the key to " << f(get_atom_v, "CAF") << endl;
} }
CAF_MAIN() CAF_MAIN()
This diff is collapsed.
...@@ -3,18 +3,18 @@ ...@@ -3,18 +3,18 @@
* exercise using only libcaf's event-based actor implementation. * * exercise using only libcaf's event-based actor implementation. *
\******************************************************************************/ \******************************************************************************/
#include <chrono>
#include <iostream>
#include <map> #include <map>
#include <sstream>
#include <thread> #include <thread>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <chrono>
#include <sstream>
#include <iostream>
#include "caf/all.hpp" #include "caf/all.hpp"
using std::cout;
using std::cerr; using std::cerr;
using std::cout;
using std::endl; using std::endl;
using std::chrono::seconds; using std::chrono::seconds;
...@@ -22,14 +22,11 @@ using namespace caf; ...@@ -22,14 +22,11 @@ using namespace caf;
namespace { namespace {
// atoms for chopstick interface // atoms for chopstick and philosopher interfaces
using put_atom = atom_constant<atom("put")>; CAF_MSG_TYPE_ADD_ATOM(take_atom);
using take_atom = atom_constant<atom("take")>; CAF_MSG_TYPE_ADD_ATOM(taken_atom);
using taken_atom = atom_constant<atom("taken")>; CAF_MSG_TYPE_ADD_ATOM(eat_atom);
CAF_MSG_TYPE_ADD_ATOM(think_atom);
// atoms for philosopher interface
using eat_atom = atom_constant<atom("eat")>;
using think_atom = atom_constant<atom("think")>;
// 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>,
...@@ -43,11 +40,9 @@ chopstick::behavior_type available_chopstick(chopstick::pointer self) { ...@@ -43,11 +40,9 @@ chopstick::behavior_type available_chopstick(chopstick::pointer self) {
return { return {
[=](take_atom) -> std::tuple<taken_atom, bool> { [=](take_atom) -> std::tuple<taken_atom, bool> {
self->become(taken_chopstick(self, self->current_sender())); self->become(taken_chopstick(self, self->current_sender()));
return std::make_tuple(taken_atom::value, true); return std::make_tuple(taken_atom_v, true);
}, },
[](put_atom) { [](put_atom) { cerr << "chopstick received unexpected 'put'" << endl; },
cerr << "chopstick received unexpected 'put'" << endl;
}
}; };
} }
...@@ -55,12 +50,12 @@ chopstick::behavior_type taken_chopstick(chopstick::pointer self, ...@@ -55,12 +50,12 @@ chopstick::behavior_type taken_chopstick(chopstick::pointer self,
const strong_actor_ptr& user) { const strong_actor_ptr& user) {
return { return {
[](take_atom) -> std::tuple<taken_atom, bool> { [](take_atom) -> std::tuple<taken_atom, bool> {
return std::make_tuple(taken_atom::value, false); return std::make_tuple(taken_atom_v, false);
}, },
[=](put_atom) { [=](put_atom) {
if (self->current_sender() == user) if (self->current_sender() == user)
self->become(available_chopstick(self)); self->become(available_chopstick(self));
} },
}; };
} }
...@@ -94,71 +89,56 @@ chopstick::behavior_type taken_chopstick(chopstick::pointer self, ...@@ -94,71 +89,56 @@ chopstick::behavior_type taken_chopstick(chopstick::pointer self,
class philosopher : public event_based_actor { class philosopher : public event_based_actor {
public: public:
philosopher(actor_config& cfg, philosopher(actor_config& cfg, std::string n, chopstick l, chopstick r)
std::string n, : event_based_actor(cfg),
chopstick l, name_(std::move(n)),
chopstick r) left_(std::move(l)),
: event_based_actor(cfg), right_(std::move(r)) {
name_(std::move(n)),
left_(std::move(l)),
right_(std::move(r)) {
// we only accept one message per state and skip others in the meantime // we only accept one message per state and skip others in the meantime
set_default_handler(skip); set_default_handler(skip);
// a philosopher that receives {eat} stops thinking and becomes hungry // a philosopher that receives {eat} stops thinking and becomes hungry
thinking_.assign( thinking_.assign([=](eat_atom) {
[=](eat_atom) { become(hungry_);
become(hungry_); send(left_, take_atom_v);
send(left_, take_atom::value); send(right_, take_atom_v);
send(right_, take_atom::value); });
}
);
// wait for the first answer of a chopstick // wait for the first answer of a chopstick
hungry_.assign( hungry_.assign([=](taken_atom, bool result) {
[=](taken_atom, bool result) { if (result)
if (result) become(granted_);
become(granted_); else
else become(denied_);
become(denied_); });
}
);
// philosopher was able to obtain the first chopstick // philosopher was able to obtain the first chopstick
granted_.assign( granted_.assign([=](taken_atom, bool result) {
[=](taken_atom, bool result) { if (result) {
if (result) { aout(this) << name_ << " has picked up chopsticks with IDs "
aout(this) << name_ << left_->id() << " and " << right_->id()
<< " has picked up chopsticks with IDs " << " and starts to eat\n";
<< left_->id() << " and " << right_->id() // eat some time
<< " and starts to eat\n"; delayed_send(this, seconds(5), think_atom_v);
// eat some time become(eating_);
delayed_send(this, seconds(5), think_atom::value); } else {
become(eating_); send(current_sender() == left_ ? right_ : left_, put_atom_v);
} else { send(this, eat_atom_v);
send(current_sender() == left_ ? right_ : left_, put_atom::value);
send(this, eat_atom::value);
become(thinking_);
}
}
);
// philosopher was *not* able to obtain the first chopstick
denied_.assign(
[=](taken_atom, bool result) {
if (result)
send(current_sender() == left_ ? left_ : right_, put_atom::value);
send(this, eat_atom::value);
become(thinking_); become(thinking_);
} }
); });
// philosopher was *not* able to obtain the first chopstick
denied_.assign([=](taken_atom, bool result) {
if (result)
send(current_sender() == left_ ? left_ : right_, put_atom_v);
send(this, eat_atom_v);
become(thinking_);
});
// philosopher obtained both chopstick and eats (for five seconds) // philosopher obtained both chopstick and eats (for five seconds)
eating_.assign( eating_.assign([=](think_atom) {
[=](think_atom) { send(left_, put_atom_v);
send(left_, put_atom::value); send(right_, put_atom_v);
send(right_, put_atom::value); delayed_send(this, seconds(5), eat_atom_v);
delayed_send(this, seconds(5), eat_atom::value); aout(this) << name_ << " puts down his chopsticks and starts to think\n";
aout(this) << name_ become(thinking_);
<< " puts down his chopsticks and starts to think\n"; });
become(thinking_);
}
);
} }
const char* name() const override { const char* name() const override {
...@@ -168,31 +148,40 @@ public: ...@@ -168,31 +148,40 @@ public:
protected: protected:
behavior make_behavior() override { behavior make_behavior() override {
// start thinking // start thinking
send(this, think_atom::value); send(this, think_atom_v);
// philosophers start to think after receiving {think} // philosophers start to think after receiving {think}
return ( return {
[=](think_atom) { [=](think_atom) {
aout(this) << name_ << " starts to think\n"; aout(this) << name_ << " starts to think\n";
delayed_send(this, seconds(5), eat_atom::value); delayed_send(this, seconds(5), eat_atom_v);
become(thinking_); become(thinking_);
} },
); };
} }
private: private:
std::string name_; // the name of this philosopher std::string name_; // the name of this philosopher
chopstick left_; // left chopstick chopstick left_; // left chopstick
chopstick right_; // right chopstick chopstick right_; // right chopstick
behavior thinking_; // initial behavior behavior thinking_; // initial behavior
behavior hungry_; // tries to take chopsticks behavior hungry_; // tries to take chopsticks
behavior granted_; // has one chopstick and waits for the second one behavior granted_; // has one chopstick and waits for the second one
behavior denied_; // could not get first chopsticks behavior denied_; // could not get first chopsticks
behavior eating_; // wait for some time, then go thinking again behavior eating_; // wait for some time, then go thinking again
};
struct config : actor_system_config {
config() {
add_message_type<take_atom>("take_atom");
add_message_type<taken_atom>("taken_atom");
add_message_type<eat_atom>("eat_atom");
add_message_type<think_atom>("think_atom");
}
}; };
} // namespace } // namespace
void caf_main(actor_system& system) { void caf_main(actor_system& system, const config&) {
scoped_actor self{system}; scoped_actor self{system};
// create five chopsticks // create five chopsticks
aout(self) << "chopstick ids are:"; aout(self) << "chopstick ids are:";
...@@ -203,8 +192,8 @@ void caf_main(actor_system& system) { ...@@ -203,8 +192,8 @@ void caf_main(actor_system& system) {
} }
aout(self) << endl; aout(self) << endl;
// spawn five philosophers // spawn five philosophers
std::vector<std::string> names {"Plato", "Hume", "Kant", std::vector<std::string> names{"Plato", "Hume", "Kant", "Nietzsche",
"Nietzsche", "Descartes"}; "Descartes"};
for (size_t i = 0; i < 5; ++i) for (size_t i = 0; i < 5; ++i)
self->spawn<philosopher>(names[i], chopsticks[i], chopsticks[(i + 1) % 5]); self->spawn<philosopher>(names[i], chopsticks[i], chopsticks[(i + 1) % 5]);
} }
......
#include "caf/all.hpp" #include "caf/all.hpp"
using namespace caf;
using idle_atom = atom_constant<atom("idle")>; using namespace caf;
using request_atom = atom_constant<atom("request")>;
using response_atom = atom_constant<atom("response")>;
behavior server(event_based_actor* self) { behavior server(event_based_actor* self) {
return { return {
[=](idle_atom, const actor& worker) { [=](idle_atom, const actor& worker) {
self->become ( self->become(
keep_behavior, keep_behavior,
[=](request_atom atm) { [=](ping_atom atm) {
self->delegate(worker, atm); self->delegate(worker, atm);
self->unbecome(); self->unbecome();
}, },
[=](idle_atom) { [=](idle_atom, const actor&) { return skip(); });
return skip();
}
);
}, },
[=](request_atom) { [=](ping_atom) { return skip(); },
return skip();
}
}; };
} }
behavior client(event_based_actor* self, const actor& serv) { behavior client(event_based_actor* self, const actor& serv) {
self->link_to(serv); self->link_to(serv);
self->send(serv, idle_atom::value, self); self->send(serv, idle_atom_v, self);
return { return {
[=](request_atom) { [=](ping_atom) {
self->send(serv, idle_atom::value, self); self->send(serv, idle_atom_v, self);
return response_atom::value; return pong_atom_v;
} },
}; };
} }
...@@ -40,20 +32,18 @@ void caf_main(actor_system& system) { ...@@ -40,20 +32,18 @@ void caf_main(actor_system& system) {
auto serv = system.spawn(server); auto serv = system.spawn(server);
auto worker = system.spawn(client, serv); auto worker = system.spawn(client, serv);
scoped_actor self{system}; scoped_actor self{system};
self->request(serv, std::chrono::seconds(10), request_atom::value).receive( self->request(serv, std::chrono::seconds(10), ping_atom_v)
[&](response_atom) { .receive(
aout(self) << "received response from " [&](pong_atom) {
<< (self->current_sender() == worker ? "worker\n" aout(self) << "received response from "
: "server\n"); << (self->current_sender() == worker ? "worker\n"
}, : "server\n");
[&](error& err) { },
aout(self) << "received error " [&](error& err) {
<< system.render(err) aout(self) << "received error " << system.render(err) << " from "
<< " from " << (self->current_sender() == worker ? "worker\n"
<< (self->current_sender() == worker ? "worker\n" : "server\n");
: "server\n"); });
}
);
self->send_exit(serv, exit_reason::user_shutdown); self->send_exit(serv, exit_reason::user_shutdown);
} }
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* for both the blocking and the event-based API. * * for both the blocking and the event-based API. *
\******************************************************************************/ \******************************************************************************/
// Manual refs: lines 19-21, 31-72, 74-108, 140-145 (Actor) // Manual refs: lines 17-18, 21-26, 28-56, 58-92, 123-128 (Actor)
#include <iostream> #include <iostream>
...@@ -14,9 +14,6 @@ using namespace caf; ...@@ -14,9 +14,6 @@ using namespace caf;
namespace { namespace {
using add_atom = atom_constant<atom("add")>;
using sub_atom = atom_constant<atom("sub")>;
using calculator_actor = typed_actor<replies_to<add_atom, int, int>::with<int>, using calculator_actor = typed_actor<replies_to<add_atom, int, int>::with<int>,
replies_to<sub_atom, int, int>::with<int>>; replies_to<sub_atom, int, int>::with<int>>;
...@@ -31,43 +28,30 @@ class typed_calculator; ...@@ -31,43 +28,30 @@ class typed_calculator;
// function-based, dynamically typed, event-based API // function-based, dynamically typed, event-based API
behavior calculator_fun(event_based_actor*) { behavior calculator_fun(event_based_actor*) {
return { return {
[](add_atom, int a, int b) { [](add_atom, int a, int b) { return a + b; },
return a + b; [](sub_atom, int a, int b) { return a - b; },
},
[](sub_atom, int a, int b) {
return a - b;
}
}; };
} }
// function-based, dynamically typed, blocking API // function-based, dynamically typed, blocking API
void blocking_calculator_fun(blocking_actor* self) { void blocking_calculator_fun(blocking_actor* self) {
bool running = true; bool running = true;
self->receive_while(running) ( self->receive_while(running)( //
[](add_atom, int a, int b) { [](add_atom, int a, int b) { return a + b; },
return a + b; [](sub_atom, int a, int b) { return a - b; },
},
[](sub_atom, int a, int b) {
return a - b;
},
[&](exit_msg& em) { [&](exit_msg& em) {
if (em.reason) { if (em.reason) {
self->fail_state(std::move(em.reason)); self->fail_state(std::move(em.reason));
running = false; running = false;
} }
} });
);
} }
// function-based, statically typed, event-based API // function-based, statically typed, event-based API
calculator_actor::behavior_type typed_calculator_fun() { calculator_actor::behavior_type typed_calculator_fun() {
return { return {
[](add_atom, int a, int b) { [](add_atom, int a, int b) { return a + b; },
return a + b; [](sub_atom, int a, int b) { return a - b; },
},
[](sub_atom, int a, int b) {
return a - b;
}
}; };
} }
...@@ -119,19 +103,19 @@ void tester(scoped_actor& self, const Handle& hdl, int x, int y, Ts&&... xs) { ...@@ -119,19 +103,19 @@ void tester(scoped_actor& self, const Handle& hdl, int x, int y, Ts&&... xs) {
<< self->system().render(err) << endl; << self->system().render(err) << endl;
}; };
// first test: x + y = z // first test: x + y = z
self->request(hdl, infinite, add_atom::value, x, y).receive( self->request(hdl, infinite, add_atom_v, x, y)
[&](int res1) { .receive(
aout(self) << x << " + " << y << " = " << res1 << endl; [&](int res1) {
// second test: x - y = z aout(self) << x << " + " << y << " = " << res1 << endl;
self->request(hdl, infinite, sub_atom::value, x, y).receive( // second test: x - y = z
[&](int res2) { self->request(hdl, infinite, sub_atom_v, x, y)
aout(self) << x << " - " << y << " = " << res2 << endl; .receive(
}, [&](int res2) {
handle_err aout(self) << x << " - " << y << " = " << res2 << endl;
); },
}, handle_err);
handle_err },
); handle_err);
tester(self, std::forward<Ts>(xs)...); tester(self, std::forward<Ts>(xs)...);
} }
......
...@@ -49,9 +49,9 @@ void caf_main(actor_system& system) { ...@@ -49,9 +49,9 @@ void caf_main(actor_system& system) {
auto cell1 = system.spawn(type_checked_cell); auto cell1 = system.spawn(type_checked_cell);
auto cell2 = system.spawn(unchecked_cell); auto cell2 = system.spawn(unchecked_cell);
auto f = make_function_view(cell1); auto f = make_function_view(cell1);
cout << "cell value: " << f(get_atom::value) << endl; cout << "cell value: " << f(get_atom_v) << endl;
f(put_atom::value, 20); f(put_atom_v, 20);
cout << "cell value (after setting to 20): " << f(get_atom::value) << endl; cout << "cell value (after setting to 20): " << f(get_atom_v) << endl;
// get an unchecked cell and send it some garbage // get an unchecked cell and send it some garbage
anon_send(cell2, "hello there!"); anon_send(cell2, "hello there!");
} }
......
/******************************************************************************\ /******************************************************************************\
* This example illustrates how to do time-triggered loops in libcaf. * * This example illustrates how to do time-triggered loops in libcaf. *
\ ******************************************************************************/ \******************************************************************************/
#include <algorithm>
#include <chrono> #include <chrono>
#include <iostream> #include <iostream>
#include <algorithm>
#include "caf/all.hpp" #include "caf/all.hpp"
// This file is partially included in the manual, do not modify // This file is partially included in the manual, do not modify
// without updating the references in the *.tex files! // without updating the references in the *.tex files!
// Manual references: lines 56-75 (MessagePassing.tex) // Manual references: lines 58-75 (MessagePassing.tex)
using std::cout; using std::cout;
using std::endl; using std::endl;
...@@ -17,23 +18,24 @@ using std::pair; ...@@ -17,23 +18,24 @@ using std::pair;
using namespace caf; using namespace caf;
using step_atom = atom_constant<atom("step")>;
// ASCII art figures // ASCII art figures
constexpr const char* figures[] = { constexpr const char* figures[] = {
"<(^.^<)", "<(^.^<)",
"<(^.^)>", "<(^.^)>",
"(>^.^)>" "(>^.^)>",
}; };
struct animation_step { size_t figure_idx; size_t offset; }; struct animation_step {
size_t figure_idx;
size_t offset;
};
// array of {figure, offset} pairs // array of {figure, offset} pairs
constexpr animation_step animation_steps[] = { constexpr animation_step animation_steps[] = {
{1, 7}, {0, 7}, {0, 6}, {0, 5}, {1, 5}, {2, 5}, {2, 6}, {1, 7}, {0, 7}, {0, 6}, {0, 5}, {1, 5}, {2, 5}, {2, 6},
{2, 7}, {2, 8}, {2, 9}, {2, 10}, {1, 10}, {0, 10}, {0, 9}, {2, 7}, {2, 8}, {2, 9}, {2, 10}, {1, 10}, {0, 10}, {0, 9},
{1, 9}, {2, 10}, {2, 11}, {2, 12}, {2, 13}, {1, 13}, {0, 13}, {1, 9}, {2, 10}, {2, 11}, {2, 12}, {2, 13}, {1, 13}, {0, 13},
{0, 12}, {0, 11}, {0, 10}, {0, 9}, {0, 8}, {0, 7}, {1, 7} {0, 12}, {0, 11}, {0, 10}, {0, 9}, {0, 8}, {0, 7}, {1, 7},
}; };
constexpr size_t animation_width = 20; constexpr size_t animation_width = 20;
...@@ -56,22 +58,20 @@ void draw_kirby(const animation_step& animation) { ...@@ -56,22 +58,20 @@ void draw_kirby(const animation_step& animation) {
// uses a message-based loop to iterate over all animation steps // uses a message-based loop to iterate over all animation steps
void dancing_kirby(event_based_actor* self) { void dancing_kirby(event_based_actor* self) {
// let's get it started // let's get it started
self->send(self, step_atom::value, size_t{0}); self->send(self, update_atom_v, size_t{0});
self->become ( self->become([=](update_atom, size_t step) {
[=](step_atom, size_t step) { if (step == sizeof(animation_step)) {
if (step == sizeof(animation_step)) { // we've printed all animation steps (done)
// we've printed all animation steps (done) cout << endl;
cout << endl; self->quit();
self->quit(); return;
return;
}
// print given step
draw_kirby(animation_steps[step]);
// animate next step in 150ms
self->delayed_send(self, std::chrono::milliseconds(150),
step_atom::value, step + 1);
} }
); // print given step
draw_kirby(animation_steps[step]);
// animate next step in 150ms
self->delayed_send(self, std::chrono::milliseconds(150), update_atom_v,
step + 1);
});
} }
void caf_main(actor_system& system) { void caf_main(actor_system& system) {
......
#include <iostream> #include <iostream>
#include "caf/all.hpp" #include "caf/all.hpp"
// This file is partially included in the manual, do not modify // This file is partially included in the manual, do not modify
// without updating the references in the *.tex files! // without updating the references in the *.tex files!
// Manual references: lines 15-42 (MessagePassing.tex) // Manual references: lines 15-36 (MessagePassing.tex)
using std::endl;
using namespace caf; using namespace caf;
// using add_atom = atom_constant<atom("add")>; (defined in atom.hpp) // using add_atom = atom_constant<atom("add")>; (defined in atom.hpp)
...@@ -13,26 +13,21 @@ using namespace caf; ...@@ -13,26 +13,21 @@ using namespace caf;
using calc = typed_actor<replies_to<add_atom, int, int>::with<int>>; using calc = typed_actor<replies_to<add_atom, int, int>::with<int>>;
void actor_a(event_based_actor* self, const calc& worker) { void actor_a(event_based_actor* self, const calc& worker) {
self->request(worker, std::chrono::seconds(10), add_atom::value, 1, 2).then( self->request(worker, std::chrono::seconds(10), add_atom_v, 1, 2)
[=](int result) { .then([=](int result) { aout(self) << "1 + 2 = " << result << std::endl; });
aout(self) << "1 + 2 = " << result << endl;
}
);
} }
calc::behavior_type actor_b(calc::pointer self, const calc& worker) { calc::behavior_type actor_b(calc::pointer self, const calc& worker) {
return { return {
[=](add_atom add, int x, int y) { [=](add_atom add, int x, int y) {
return self->delegate(worker, add, x, y); return self->delegate(worker, add, x, y);
} },
}; };
} }
calc::behavior_type actor_c() { calc::behavior_type actor_c() {
return { return {
[](add_atom, int x, int y) { [](add_atom, int x, int y) { return x + y; },
return x + y;
}
}; };
} }
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
* A very basic, interactive divider. * * A very basic, interactive divider. *
\******************************************************************************/ \******************************************************************************/
// Manual refs: 19-25, 35-48, 68-77 (MessagePassing); // Manual refs: 17-19, 49-59, 70-76 (MessagePassing);
// 19-34, 50-58 (Error) // 17-47 (Error)
#include <iostream> #include <iostream>
...@@ -14,16 +14,10 @@ using std::endl; ...@@ -14,16 +14,10 @@ using std::endl;
using std::flush; using std::flush;
using namespace caf; using namespace caf;
namespace {
enum class math_error : uint8_t { enum class math_error : uint8_t {
division_by_zero = 1 division_by_zero = 1,
}; };
error make_error(math_error x) {
return {static_cast<uint8_t>(x), atom("math")};
}
std::string to_string(math_error x) { std::string to_string(math_error x) {
switch (x) { switch (x) {
case math_error::division_by_zero: case math_error::division_by_zero:
...@@ -33,7 +27,24 @@ std::string to_string(math_error x) { ...@@ -33,7 +27,24 @@ std::string to_string(math_error x) {
} }
} }
using div_atom = atom_constant<atom("div")>; namespace caf {
template <>
struct error_category<math_error> {
static constexpr uint8_t value = 101;
};
} // namespace caf
class config : public actor_system_config {
public:
config() {
auto renderer = [](uint8_t x, const message&) {
return to_string(static_cast<math_error>(x));
};
add_error_category(caf::error_category<math_error>::value, renderer);
}
};
using divider = typed_actor<replies_to<div_atom, double, double>::with<double>>; using divider = typed_actor<replies_to<div_atom, double, double>::with<double>>;
...@@ -43,20 +54,10 @@ divider::behavior_type divider_impl() { ...@@ -43,20 +54,10 @@ divider::behavior_type divider_impl() {
if (y == 0.0) if (y == 0.0)
return math_error::division_by_zero; return math_error::division_by_zero;
return x / y; return x / y;
} },
}; };
} }
class config : public actor_system_config {
public:
config() {
auto renderer = [](uint8_t x, atom_value, const message&) {
return "math_error" + deep_to_string_as_tuple(static_cast<math_error>(x));
};
add_error_category(atom("math"), renderer);
}
};
void caf_main(actor_system& system, const config&) { void caf_main(actor_system& system, const config&) {
double x; double x;
double y; double y;
...@@ -66,17 +67,13 @@ void caf_main(actor_system& system, const config&) { ...@@ -66,17 +67,13 @@ void caf_main(actor_system& system, const config&) {
std::cin >> y; std::cin >> y;
auto div = system.spawn(divider_impl); auto div = system.spawn(divider_impl);
scoped_actor self{system}; scoped_actor self{system};
self->request(div, std::chrono::seconds(10), div_atom::value, x, y).receive( self->request(div, std::chrono::seconds(10), div_atom_v, x, y)
[&](double z) { .receive(
aout(self) << x << " / " << y << " = " << z << endl; [&](double z) { aout(self) << x << " / " << y << " = " << z << endl; },
}, [&](const error& err) {
[&](const error& err) { aout(self) << "*** cannot compute " << x << " / " << y << " => "
aout(self) << "*** cannot compute " << x << " / " << y << " => " << system.render(err) << endl;
<< system.render(err) << endl; });
}
);
} }
} // namespace
CAF_MAIN() CAF_MAIN()
...@@ -4,9 +4,9 @@ ...@@ -4,9 +4,9 @@
#include <cassert> #include <cassert>
#include <chrono> #include <chrono>
#include <cmath>
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
#include <numeric>
#include <vector> #include <vector>
#include "caf/actor_system.hpp" #include "caf/actor_system.hpp"
...@@ -24,9 +24,9 @@ using std::endl; ...@@ -24,9 +24,9 @@ using std::endl;
using std::chrono::seconds; using std::chrono::seconds;
using namespace caf; using namespace caf;
using row_atom = atom_constant<atom("row")>; CAF_MSG_TYPE_ADD_ATOM(row_atom);
using column_atom = atom_constant<atom("column")>; CAF_MSG_TYPE_ADD_ATOM(column_atom);
using average_atom = atom_constant<atom("average")>; 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<
...@@ -122,7 +122,15 @@ std::ostream& operator<<(std::ostream& out, const expected<int>& x) { ...@@ -122,7 +122,15 @@ std::ostream& operator<<(std::ostream& out, const expected<int>& x) {
return out << to_string(x.error()); return out << to_string(x.error());
} }
void caf_main(actor_system& sys) { struct config : actor_system_config {
config() {
add_message_type<row_atom>("row_atom");
add_message_type<column_atom>("column_atom");
add_message_type<average_atom>("average_atom");
}
};
void caf_main(actor_system& sys, const config&) {
// Spawn our matrix. // Spawn our matrix.
static constexpr int rows = 3; static constexpr int rows = 3;
static constexpr int columns = 6; static constexpr int columns = 6;
...@@ -134,22 +142,21 @@ void caf_main(actor_system& sys) { ...@@ -134,22 +142,21 @@ void caf_main(actor_system& sys) {
// 4 16 64 256 1024 4096 // 4 16 64 256 1024 4096
for (int row = 0; row < rows; ++row) for (int row = 0; row < rows; ++row)
for (int column = 0; column < columns; ++column) for (int column = 0; column < columns; ++column)
f(put_atom::value, row, column, (int) pow(row + 2, column + 1)); f(put_atom_v, row, column, (int) pow(row + 2, column + 1));
// Print out matrix. // Print out matrix.
for (int row = 0; row < rows; ++row) { for (int row = 0; row < rows; ++row) {
for (int column = 0; column < columns; ++column) for (int column = 0; column < columns; ++column)
std::cout << std::setw(4) << f(get_atom::value, row, column) << ' '; std::cout << std::setw(4) << f(get_atom_v, row, column) << ' ';
std::cout << '\n'; std::cout << '\n';
} }
// Print out AVG for each row and column. // Print out AVG for each row and column.
for (int row = 0; row < rows; ++row) for (int row = 0; row < rows; ++row)
std::cout << "AVG(row " << row << ") = " std::cout << "AVG(row " << row
<< f(get_atom::value, average_atom::value, row_atom::value, row) << ") = " << f(get_atom_v, average_atom_v, row_atom_v, row)
<< '\n'; << '\n';
for (int column = 0; column < columns; ++column) for (int column = 0; column < columns; ++column)
std::cout << "AVG(column " << column << ") = " std::cout << "AVG(column " << column
<< f(get_atom::value, average_atom::value, column_atom::value, << ") = " << f(get_atom_v, average_atom_v, column_atom_v, column)
column)
<< '\n'; << '\n';
} }
......
#include "caf/all.hpp"
#include <cassert> #include <cassert>
#include <cstdint> #include <cstdint>
#include <iostream> #include <iostream>
#include "caf/all.hpp"
using std::endl; using std::endl;
using namespace caf; using namespace caf;
namespace { namespace {
using pop_atom = atom_constant<atom("pop")>; CAF_MSG_TYPE_ADD_ATOM(pop_atom);
using push_atom = atom_constant<atom("push")>; CAF_MSG_TYPE_ADD_ATOM(push_atom);
enum class fixed_stack_errc : uint8_t { push_to_full = 1, pop_from_empty }; enum class fixed_stack_errc : uint8_t {
push_to_full = 1,
pop_from_empty,
};
error make_error(fixed_stack_errc x) { } // namespace
return error{static_cast<uint8_t>(x), atom("FixedStack")};
} namespace caf {
template <>
struct error_category<fixed_stack_errc> {
static constexpr uint8_t value = 100;
};
} // 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)
: event_based_actor(cfg), : event_based_actor(cfg), size_(stack_size) {
size_(stack_size) { full_.assign( //
full_.assign( [=](push_atom, int) -> error { return fixed_stack_errc::push_to_full; },
[=](push_atom, int) -> error {
return fixed_stack_errc::push_to_full;
},
[=](pop_atom) -> int { [=](pop_atom) -> int {
auto result = data_.back(); auto result = data_.back();
data_.pop_back(); data_.pop_back();
become(filled_); become(filled_);
return result; return result;
} });
); filled_.assign( //
filled_.assign(
[=](push_atom, int what) { [=](push_atom, int what) {
data_.push_back(what); data_.push_back(what);
if (data_.size() == size_) if (data_.size() == size_)
...@@ -45,17 +53,13 @@ public: ...@@ -45,17 +53,13 @@ public:
if (data_.empty()) if (data_.empty())
become(empty_); become(empty_);
return result; return result;
} });
); empty_.assign( //
empty_.assign(
[=](push_atom, int what) { [=](push_atom, int what) {
data_.push_back(what); data_.push_back(what);
become(filled_); become(filled_);
}, },
[=](pop_atom) -> error { [=](pop_atom) -> error { return fixed_stack_errc::pop_from_empty; });
return fixed_stack_errc::pop_from_empty;
}
);
} }
behavior make_behavior() override { behavior make_behavior() override {
...@@ -76,19 +80,14 @@ void caf_main(actor_system& system) { ...@@ -76,19 +80,14 @@ void caf_main(actor_system& system) {
auto st = self->spawn<fixed_stack>(5u); auto st = self->spawn<fixed_stack>(5u);
// fill stack // fill stack
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i)
self->send(st, push_atom::value, i); self->send(st, push_atom_v, i);
// drain stack // drain stack
aout(self) << "stack: { "; aout(self) << "stack: { ";
bool stack_empty = false; bool stack_empty = false;
while (!stack_empty) { while (!stack_empty) {
self->request(st, std::chrono::seconds(10), pop_atom::value).receive( self->request(st, std::chrono::seconds(10), pop_atom_v)
[&](int x) { .receive([&](int x) { aout(self) << x << " "; },
aout(self) << x << " "; [&](const error&) { stack_empty = true; });
},
[&](const error&) {
stack_empty = true;
}
);
} }
aout(self) << "}" << endl; aout(self) << "}" << endl;
self->send_exit(st, exit_reason::user_shutdown); self->send_exit(st, exit_reason::user_shutdown);
......
...@@ -44,7 +44,7 @@ adder::behavior_type calculator_master(adder::pointer self) { ...@@ -44,7 +44,7 @@ adder::behavior_type calculator_master(adder::pointer self) {
void caf_main(actor_system& system) { void caf_main(actor_system& system) {
auto f = make_function_view(system.spawn(calculator_master)); auto f = make_function_view(system.spawn(calculator_master));
cout << "12 + 13 = " << f(add_atom::value, 12, 13) << endl; cout << "12 + 13 = " << f(add_atom_v, 12, 13) << endl;
} }
CAF_MAIN() CAF_MAIN()
...@@ -38,29 +38,27 @@ cell::behavior_type cell_impl(cell::stateful_pointer<cell_state> self, int x0) { ...@@ -38,29 +38,27 @@ cell::behavior_type cell_impl(cell::stateful_pointer<cell_state> self, int x0) {
void waiting_testee(event_based_actor* self, vector<cell> cells) { void waiting_testee(event_based_actor* self, vector<cell> cells) {
for (auto& x : cells) for (auto& x : cells)
self->request(x, seconds(1), get_atom::value).await([=](int y) { self->request(x, seconds(1), get_atom_v).await([=](int y) {
aout(self) << "cell #" << x.id() << " -> " << y << endl; aout(self) << "cell #" << x.id() << " -> " << y << endl;
}); });
} }
void multiplexed_testee(event_based_actor* self, vector<cell> cells) { void multiplexed_testee(event_based_actor* self, vector<cell> cells) {
for (auto& x : cells) for (auto& x : cells)
self->request(x, seconds(1), get_atom::value).then([=](int y) { self->request(x, seconds(1), get_atom_v).then([=](int y) {
aout(self) << "cell #" << x.id() << " -> " << y << endl; aout(self) << "cell #" << x.id() << " -> " << y << endl;
}); });
} }
void blocking_testee(blocking_actor* self, vector<cell> cells) { void blocking_testee(blocking_actor* self, vector<cell> cells) {
for (auto& x : cells) for (auto& x : cells)
self->request(x, seconds(1), get_atom::value).receive( self->request(x, seconds(1), get_atom_v)
[&](int y) { .receive(
aout(self) << "cell #" << x.id() << " -> " << y << endl; [&](int y) { aout(self) << "cell #" << x.id() << " -> " << y << endl; },
}, [&](error& err) {
[&](error& err) { aout(self) << "cell #" << x.id() << " -> "
aout(self) << "cell #" << x.id() << self->system().render(err) << endl;
<< " -> " << self->system().render(err) << endl; });
}
);
} }
void caf_main(actor_system& system) { void caf_main(actor_system& system) {
......
/******************************************************************************\ /******************************************************************************\
* This example is a very basic, non-interactive math service implemented * * This example is a very basic, non-interactive math service implemented *
* using typed actors. * * using typed actors. *
\ ******************************************************************************/ \******************************************************************************/
#include "caf/all.hpp"
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
#include "caf/all.hpp"
using std::endl; using std::endl;
using namespace caf; using namespace caf;
namespace { namespace {
using plus_atom = atom_constant<atom("plus")>; using calculator_type = typed_actor<replies_to<add_atom, int, int>::with<int>,
using minus_atom = atom_constant<atom("minus")>; replies_to<sub_atom, int, int>::with<int>>;
using result_atom = atom_constant<atom("result")>;
using calculator_type =
typed_actor<replies_to<plus_atom, int, int>::with<result_atom, int>,
replies_to<minus_atom, int, int>::with<result_atom, int>>;
calculator_type::behavior_type typed_calculator_fun(calculator_type::pointer) { calculator_type::behavior_type typed_calculator_fun(calculator_type::pointer) {
return { return {
[](plus_atom, int x, int y) { [](add_atom, int x, int y) { return x + y; },
return std::make_tuple(result_atom::value, x + y); [](sub_atom, int x, int y) { return x - y; },
},
[](minus_atom, int x, int y) {
return std::make_tuple(result_atom::value, x - y);
}
}; };
} }
...@@ -40,12 +31,8 @@ public: ...@@ -40,12 +31,8 @@ public:
protected: protected:
behavior_type make_behavior() override { behavior_type make_behavior() override {
return { return {
[](plus_atom, int x, int y) { [](add_atom, int x, int y) { return x + y; },
return std::make_tuple(result_atom::value, x + y); [](sub_atom, int x, int y) { return x - y; },
},
[](minus_atom, int x, int y) {
return std::make_tuple(result_atom::value, x - y);
}
}; };
} }
}; };
...@@ -53,26 +40,23 @@ protected: ...@@ -53,26 +40,23 @@ protected:
void tester(event_based_actor* self, const calculator_type& testee) { void tester(event_based_actor* self, const calculator_type& testee) {
self->link_to(testee); self->link_to(testee);
// first test: 2 + 1 = 3 // first test: 2 + 1 = 3
self->request(testee, infinite, plus_atom::value, 2, 1).then( self->request(testee, infinite, add_atom_v, 2, 1)
[=](result_atom, int r1) { .then(
// second test: 2 - 1 = 1 [=](int r1) {
self->request(testee, infinite, minus_atom::value, 2, 1).then( // second test: 2 - 1 = 1
[=](result_atom, int r2) { self->request(testee, infinite, sub_atom_v, 2, 1).then([=](int r2) {
// both tests succeeded // both tests succeeded
if (r1 == 3 && r2 == 1) { if (r1 == 3 && r2 == 1) {
aout(self) << "AUT (actor under test) seems to be ok" aout(self) << "AUT (actor under test) seems to be ok" << endl;
<< endl;
} }
self->send_exit(testee, exit_reason::user_shutdown); self->send_exit(testee, exit_reason::user_shutdown);
} });
); },
}, [=](const error& err) {
[=](const error& err) { aout(self) << "AUT (actor under test) failed: "
aout(self) << "AUT (actor under test) failed: " << self->system().render(err) << endl;
<< self->system().render(err) << endl; self->quit(exit_reason::user_shutdown);
self->quit(exit_reason::user_shutdown); });
}
);
} }
void caf_main(actor_system& system) { void caf_main(actor_system& system) {
......
...@@ -9,21 +9,21 @@ ...@@ -9,21 +9,21 @@
// Run client at the same host: // Run client at the same host:
// - ./build/bin/distributed_math_actor -c -p 4242 // - ./build/bin/distributed_math_actor -c -p 4242
// Manual refs: 222-234 (ConfiguringActorSystems) // Manual refs: 206-218 (ConfiguringActorSystems)
#include <array> #include <array>
#include <vector>
#include <string>
#include <sstream>
#include <cassert> #include <cassert>
#include <iostream>
#include <functional> #include <functional>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include "caf/all.hpp" #include "caf/all.hpp"
#include "caf/io/all.hpp" #include "caf/io/all.hpp"
using std::cout;
using std::cerr; using std::cerr;
using std::cout;
using std::endl; using std::endl;
using std::string; using std::string;
...@@ -33,18 +33,11 @@ namespace { ...@@ -33,18 +33,11 @@ namespace {
constexpr auto task_timeout = std::chrono::seconds(10); constexpr auto task_timeout = std::chrono::seconds(10);
using plus_atom = atom_constant<atom("plus")>;
using minus_atom = atom_constant<atom("minus")>;
// our "service" // our "service"
behavior calculator_fun() { behavior calculator_fun() {
return { return {
[](plus_atom, int a, int b) { [](add_atom, int a, int b) { return a + b; },
return a + b; [](sub_atom, int a, int b) { return a - b; },
},
[](minus_atom, int a, int b) {
return a - b;
}
}; };
} }
...@@ -77,7 +70,7 @@ namespace client { ...@@ -77,7 +70,7 @@ namespace client {
// a simple calculator task: operation + operands // a simple calculator task: operation + operands
struct task { struct task {
atom_value op; caf::variant<add_atom, sub_atom> op;
int lhs; int lhs;
int rhs; int rhs;
}; };
...@@ -92,8 +85,7 @@ struct state { ...@@ -92,8 +85,7 @@ struct state {
behavior unconnected(stateful_actor<state>*); behavior unconnected(stateful_actor<state>*);
// prototype definition for transition to `connecting` with Host and Port // prototype definition for transition to `connecting` with Host and Port
void connecting(stateful_actor<state>*, void connecting(stateful_actor<state>*, const std::string& host, uint16_t port);
const std::string& host, uint16_t port);
// prototype definition for transition to `running` with Calculator // prototype definition for transition to `running` with Calculator
behavior running(stateful_actor<state>*, const actor& calculator); behavior running(stateful_actor<state>*, const actor& calculator);
...@@ -113,78 +105,80 @@ behavior init(stateful_actor<state>* self) { ...@@ -113,78 +105,80 @@ behavior init(stateful_actor<state>* self) {
behavior unconnected(stateful_actor<state>* self) { behavior unconnected(stateful_actor<state>* self) {
return { return {
[=](plus_atom op, int x, int y) { [=](add_atom op, int x, int y) {
self->state.tasks.emplace_back(task{op, x, y}); self->state.tasks.emplace_back(task{op, x, y});
}, },
[=](minus_atom op, int x, int y) { [=](sub_atom op, int x, int y) {
self->state.tasks.emplace_back(task{op, x, y}); self->state.tasks.emplace_back(task{op, x, y});
}, },
[=](connect_atom, const std::string& host, uint16_t port) { [=](connect_atom, const std::string& host, uint16_t port) {
connecting(self, host, port); connecting(self, host, port);
} },
}; };
} }
void connecting(stateful_actor<state>* self, void connecting(stateful_actor<state>* self, const std::string& host,
const std::string& host, uint16_t port) { uint16_t port) {
// make sure we are not pointing to an old server // make sure we are not pointing to an old server
self->state.current_server = nullptr; self->state.current_server = nullptr;
// use request().await() to suspend regular behavior until MM responded // use request().await() to suspend regular behavior until MM responded
auto mm = self->system().middleman().actor_handle(); auto mm = self->system().middleman().actor_handle();
self->request(mm, infinite, connect_atom::value, host, port).await( self->request(mm, infinite, connect_atom_v, host, port)
[=](const node_id&, strong_actor_ptr serv, .await(
const std::set<std::string>& ifs) { [=](const node_id&, strong_actor_ptr serv,
if (!serv) { const std::set<std::string>& ifs) {
aout(self) << R"(*** no server found at ")" << host << R"(":)" if (!serv) {
<< port << endl; aout(self) << R"(*** no server found at ")" << host << R"(":)" << port
return; << endl;
} return;
if (!ifs.empty()) { }
aout(self) << R"(*** typed actor found at ")" << host << R"(":)" if (!ifs.empty()) {
<< port << ", but expected an untyped actor "<< endl; aout(self) << R"(*** typed actor found at ")" << host << R"(":)"
return; << port << ", but expected an untyped actor " << endl;
} return;
aout(self) << "*** successfully connected to server" << endl; }
self->state.current_server = serv; aout(self) << "*** successfully connected to server" << endl;
auto hdl = actor_cast<actor>(serv); self->state.current_server = serv;
self->monitor(hdl); auto hdl = actor_cast<actor>(serv);
self->become(running(self, hdl)); self->monitor(hdl);
}, self->become(running(self, hdl));
[=](const error& err) { },
aout(self) << R"(*** cannot connect to ")" << host << R"(":)" [=](const error& err) {
<< port << " => " << self->system().render(err) << endl; aout(self) << R"(*** cannot connect to ")" << host << R"(":)" << port
self->become(unconnected(self)); << " => " << self->system().render(err) << endl;
} self->become(unconnected(self));
); });
} }
// prototype definition for transition to `running` with Calculator // prototype definition for transition to `running` with Calculator
behavior running(stateful_actor<state>* self, const actor& calculator) { behavior running(stateful_actor<state>* self, const actor& calculator) {
auto send_task = [=](const task& x) { auto send_task = [=](auto op, int x, int y) {
self->request(calculator, task_timeout, x.op, x.lhs, x.rhs).then( self->request(calculator, task_timeout, op, x, y)
[=](int result) { .then(
aout(self) << x.lhs << (x.op == plus_atom::value ? " + " : " - ") [=](int result) {
<< x.rhs << " = " << result << endl; const char* op_str;
}, if constexpr (std::is_same<add_atom, decltype(op)>::value)
[=](const error&) { op_str = " + ";
// simply try again by enqueueing the task to the mailbox again else
self->send(self, x.op, x.lhs, x.rhs); op_str = " - ";
} aout(self) << x << op_str << y << " = " << result << endl;
); },
[=](const error&) {
// simply try again by enqueueing the task to the mailbox again
self->send(self, op, x, y);
});
}; };
for (auto& x : self->state.tasks) for (auto& x : self->state.tasks) {
send_task(x); auto f = [&](auto op) { send_task(op, x.lhs, x.rhs); };
caf::visit(f, x.op);
}
self->state.tasks.clear(); self->state.tasks.clear();
return { return {
[=](plus_atom op, int x, int y) { [=](add_atom op, int x, int y) { send_task(op, x, y); },
send_task(task{op, x, y}); [=](sub_atom op, int x, int y) { send_task(op, x, y); },
},
[=](minus_atom op, int x, int y) {
send_task(task{op, x, y});
},
[=](connect_atom, const std::string& host, uint16_t port) { [=](connect_atom, const std::string& host, uint16_t port) {
connecting(self, host, port); connecting(self, host, port);
} },
}; };
} }
...@@ -209,15 +203,6 @@ optional<int> toint(const string& str) { ...@@ -209,15 +203,6 @@ optional<int> toint(const string& str) {
return none; return none;
} }
// converts "+" to the atom '+' and "-" to the atom '-'
optional<atom_value> plus_or_minus(const string& str) {
if (str == "+")
return plus_atom::value;
if (str == "-")
return minus_atom::value;
return none;
}
class config : public actor_system_config { class config : public actor_system_config {
public: public:
uint16_t port = 0; uint16_t port = 0;
...@@ -226,27 +211,27 @@ public: ...@@ -226,27 +211,27 @@ public:
config() { config() {
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 host (ignored in server mode)") .add(host, "host,H", "set host (ignored in server mode)")
.add(server_mode, "server-mode,s", "enable server mode"); .add(server_mode, "server-mode,s", "enable server mode");
} }
}; };
void client_repl(actor_system& system, const config& cfg) { void client_repl(actor_system& system, const config& cfg) {
// keeps track of requests and tries to reconnect on server failures // keeps track of requests and tries to reconnect on server failures
auto usage = [] { auto usage = [] {
cout << "Usage:" << endl cout << "Usage:" << endl
<< " quit : terminates the program" << endl << " quit : terminates the program" << endl
<< " connect <host> <port> : connects to a remote actor" << endl << " connect <host> <port> : connects to a remote actor" << endl
<< " <x> + <y> : adds two integers" << endl << " <x> + <y> : adds two integers" << endl
<< " <x> - <y> : subtracts two integers" << endl << " <x> - <y> : subtracts two integers" << endl
<< endl; << endl;
}; };
usage(); usage();
bool done = false; bool done = false;
auto client = system.spawn(client::init); auto client = system.spawn(client::init);
if (!cfg.host.empty() && cfg.port > 0) if (!cfg.host.empty() && cfg.port > 0)
anon_send(client, connect_atom::value, cfg.host, cfg.port); anon_send(client, connect_atom_v, cfg.host, cfg.port);
else else
cout << "*** no server received via config, " cout << "*** no server received via config, "
<< R"(please use "connect <host> <port>" before using the calculator)" << R"(please use "connect <host> <port>" before using the calculator)"
...@@ -270,18 +255,19 @@ void client_repl(actor_system& system, const config& cfg) { ...@@ -270,18 +255,19 @@ void client_repl(actor_system& system, const config& cfg) {
cout << R"(")" << arg2 << R"(" > )" cout << R"(")" << arg2 << R"(" > )"
<< std::numeric_limits<uint16_t>::max() << endl; << std::numeric_limits<uint16_t>::max() << endl;
else else
anon_send(client, connect_atom::value, move(arg1), anon_send(client, connect_atom_v, move(arg1),
static_cast<uint16_t>(lport)); static_cast<uint16_t>(lport));
} } else {
else {
auto x = toint(arg0); auto x = toint(arg0);
auto op = plus_or_minus(arg1);
auto y = toint(arg2); auto y = toint(arg2);
if (x && y && op) if (x && y) {
anon_send(client, *op, *x, *y); if (arg1 == "+")
anon_send(client, add_atom_v, *x, *y);
else if (arg1 == "-")
anon_send(client, sub_atom_v, *x, *y);
}
} }
} }};
};
// read next line, split it, and feed to the eval handler // read next line, split it, and feed to the eval handler
string line; string line;
while (!done && std::getline(std::cin, line)) { while (!done && std::getline(std::cin, line)) {
...@@ -299,8 +285,8 @@ void run_server(actor_system& system, const config& cfg) { ...@@ -299,8 +285,8 @@ void run_server(actor_system& system, const config& cfg) {
cout << "*** try publish at port " << cfg.port << endl; cout << "*** try publish at port " << cfg.port << endl;
auto expected_port = io::publish(calc, cfg.port); auto expected_port = io::publish(calc, cfg.port);
if (!expected_port) { if (!expected_port) {
std::cerr << "*** publish failed: " std::cerr << "*** publish failed: " << system.render(expected_port.error())
<< system.render(expected_port.error()) << endl; << endl;
return; return;
} }
cout << "*** server successfully published at port " << *expected_port << endl cout << "*** server successfully published at port " << *expected_port << endl
......
...@@ -6,14 +6,14 @@ ...@@ -6,14 +6,14 @@
* - ./build/bin/group_chat -s -p 4242 * * - ./build/bin/group_chat -s -p 4242 *
* - ./build/bin/group_chat -g remote:chatroom@localhost:4242 -n alice * * - ./build/bin/group_chat -g remote:chatroom@localhost:4242 -n alice *
* - ./build/bin/group_chat -g remote:chatroom@localhost:4242 -n bob * * - ./build/bin/group_chat -g remote:chatroom@localhost:4242 -n bob *
\ ******************************************************************************/ \******************************************************************************/
#include <set>
#include <map>
#include <vector>
#include <cstdlib> #include <cstdlib>
#include <sstream>
#include <iostream> #include <iostream>
#include <map>
#include <set>
#include <sstream>
#include <vector>
#include "caf/all.hpp" #include "caf/all.hpp"
#include "caf/io/all.hpp" #include "caf/io/all.hpp"
...@@ -25,9 +25,11 @@ using namespace caf; ...@@ -25,9 +25,11 @@ using namespace caf;
namespace { namespace {
using broadcast_atom = atom_constant<atom("broadcast")>; CAF_MSG_TYPE_ADD_ATOM(broadcast_atom);
struct line { string str; }; struct line {
string str;
};
istream& operator>>(istream& is, line& l) { istream& operator>>(istream& is, line& l) {
getline(is, l.str); getline(is, l.str);
...@@ -37,7 +39,7 @@ istream& operator>>(istream& is, line& l) { ...@@ -37,7 +39,7 @@ istream& operator>>(istream& is, line& l) {
behavior client(event_based_actor* self, const string& name) { behavior client(event_based_actor* self, const string& name) {
return { return {
[=](broadcast_atom, const string& message) { [=](broadcast_atom, const string& message) {
for(auto& dest : self->joined_groups()) { for (auto& dest : self->joined_groups()) {
self->send(dest, name + ": " + message); self->send(dest, name + ": " + message);
} }
}, },
...@@ -58,7 +60,7 @@ behavior client(event_based_actor* self, const string& name) { ...@@ -58,7 +60,7 @@ behavior client(event_based_actor* self, const string& name) {
}, },
[=](const group_down_msg& g) { [=](const group_down_msg& g) {
cout << "*** chatroom offline: " << to_string(g.source) << endl; cout << "*** chatroom offline: " << to_string(g.source) << endl;
} },
}; };
} }
...@@ -71,16 +73,16 @@ public: ...@@ -71,16 +73,16 @@ public:
config() { config() {
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")
.add(server_mode, "server,s", "run in server mode") .add(server_mode, "server,s", "run in server mode")
.add(port, "port,p", "set port (ignored in client mode)"); .add(port, "port,p", "set port (ignored in client mode)");
} }
}; };
void run_server(actor_system& system, const config& cfg) { 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()) << endl;
return; return;
...@@ -106,7 +108,7 @@ void run_client(actor_system& system, const config& cfg) { ...@@ -106,7 +108,7 @@ void run_client(actor_system& system, const config& cfg) {
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::value, 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: )" cerr << R"(*** failed to parse ")" << uri << R"(" as group URI: )"
<< system.render(tmp.error()) << endl; << system.render(tmp.error()) << endl;
...@@ -116,36 +118,35 @@ void run_client(actor_system& system, const config& cfg) { ...@@ -116,36 +118,35 @@ void run_client(actor_system& system, const config& cfg) {
for (istream_iterator<line> i(cin); i != eof; ++i) { for (istream_iterator<line> i(cin); i != eof; ++i) {
auto send_input = [&] { auto send_input = [&] {
if (!i->str.empty()) if (!i->str.empty())
anon_send(client_actor, broadcast_atom::value, 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_builder(words.begin(), words.end()).apply({ auto res
[&](const string& cmd, const string& mod, const string& id) { = message_builder(words.begin(), words.end())
if (cmd == "/join") { .apply(
auto grp = system.groups().get(mod, id); {[&](const string& cmd, const string& mod, const string& id) {
if (grp) if (cmd == "/join") {
anon_send(client_actor, join_atom::value, *grp); auto grp = system.groups().get(mod, id);
} if (grp)
else { anon_send(client_actor, join_atom_v, *grp);
send_input(); } else {
} send_input();
}, }
[&](const string& cmd) { },
if (cmd == "/quit") { [&](const string& cmd) {
cin.setstate(ios_base::eofbit); if (cmd == "/quit") {
} cin.setstate(ios_base::eofbit);
else if (cmd[0] == '/') { } else if (cmd[0] == '/') {
cout << "*** available commands:\n" 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" << flush; " /help print this text\n"
} << flush;
else { } else {
send_input(); send_input();
} }
} }});
});
if (!res) if (!res)
send_input(); send_input();
} }
......
...@@ -7,22 +7,22 @@ ...@@ -7,22 +7,22 @@
// 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-39, 99-101,106,110 (ConfiguringActorApplications) // Manual refs: 33-34, 98-109 (ConfiguringActorApplications)
// 125-143 (RemoteSpawn) // 123-137 (RemoteSpawn)
#include <array> #include <array>
#include <vector>
#include <string>
#include <sstream>
#include <cassert> #include <cassert>
#include <iostream>
#include <functional> #include <functional>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include "caf/all.hpp" #include "caf/all.hpp"
#include "caf/io/all.hpp" #include "caf/io/all.hpp"
using std::cout;
using std::cerr; using std::cerr;
using std::cout;
using std::endl; using std::endl;
using std::string; using std::string;
...@@ -30,9 +30,6 @@ using namespace caf; ...@@ -30,9 +30,6 @@ using namespace caf;
namespace { namespace {
using add_atom = atom_constant<atom("add")>;
using sub_atom = atom_constant<atom("sub")>;
using calculator = typed_actor<replies_to<add_atom, int, int>::with<int>, using calculator = typed_actor<replies_to<add_atom, int, int>::with<int>,
replies_to<sub_atom, int, int>::with<int>>; replies_to<sub_atom, int, int>::with<int>>;
...@@ -45,7 +42,7 @@ calculator::behavior_type calculator_fun(calculator::pointer self) { ...@@ -45,7 +42,7 @@ calculator::behavior_type calculator_fun(calculator::pointer self) {
[=](sub_atom, int a, int b) -> int { [=](sub_atom, int a, int b) -> int {
aout(self) << "received task from a remote node" << endl; aout(self) << "received task from a remote node" << endl;
return a - b; return a - b;
} },
}; };
} }
...@@ -62,10 +59,11 @@ string trim(string s) { ...@@ -62,10 +59,11 @@ string trim(string s) {
// implements our main loop for reading user input // implements our main loop for reading user input
void client_repl(function_view<calculator> f) { void client_repl(function_view<calculator> f) {
auto usage = [] { auto usage = [] {
cout << "Usage:" << endl cout << "Usage:" << endl
<< " quit : terminate program" << endl << " quit : terminate program" << endl
<< " <x> + <y> : adds two integers" << endl << " <x> + <y> : adds two integers" << endl
<< " <x> - <y> : subtracts two integers" << endl << endl; << " <x> - <y> : subtracts two integers" << endl
<< endl;
}; };
usage(); usage();
// read next line, split it, and evaluate user input // read next line, split it, and evaluate user input
...@@ -91,8 +89,9 @@ void client_repl(function_view<calculator> f) { ...@@ -91,8 +89,9 @@ void client_repl(function_view<calculator> f) {
if (!x || !y || (words[1] != "+" && words[1] != "-")) if (!x || !y || (words[1] != "+" && words[1] != "-"))
usage(); usage();
else else
cout << " = " << (words[1] == "+" ? f(add_atom::value, *x, *y) cout << " = "
: f(sub_atom::value, *x, *y)) << "\n"; << (words[1] == "+" ? f(add_atom_v, *x, *y) : f(sub_atom_v, *x, *y))
<< "\n";
} }
} }
...@@ -100,9 +99,9 @@ struct config : actor_system_config { ...@@ -100,9 +99,9 @@ struct config : actor_system_config {
config() { config() {
add_actor_type("calculator", calculator_fun); add_actor_type("calculator", calculator_fun);
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)")
.add(server_mode, "server-mode,s", "enable server mode"); .add(server_mode, "server-mode,s", "enable server mode");
} }
uint16_t port = 0; uint16_t port = 0;
string host = "localhost"; string host = "localhost";
...@@ -112,12 +111,10 @@ struct config : actor_system_config { ...@@ -112,12 +111,10 @@ struct config : actor_system_config {
void server(actor_system& system, const config& cfg) { void server(actor_system& system, const config& cfg) {
auto res = system.middleman().open(cfg.port); auto res = system.middleman().open(cfg.port);
if (!res) { if (!res) {
cerr << "*** cannot open port: " cerr << "*** cannot open port: " << system.render(res.error()) << endl;
<< system.render(res.error()) << endl;
return; return;
} }
cout << "*** running on port: " cout << "*** running on port: " << *res << endl
<< *res << endl
<< "*** press <enter> to shutdown server" << endl; << "*** press <enter> to shutdown server" << endl;
getchar(); getchar();
} }
...@@ -125,18 +122,17 @@ void server(actor_system& system, const config& cfg) { ...@@ -125,18 +122,17 @@ void server(actor_system& system, const config& cfg) {
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) {
cerr << "*** connect failed: " cerr << "*** connect failed: " << system.render(node.error()) << endl;
<< system.render(node.error()) << endl;
return; return;
} }
auto type = "calculator"; // type of the actor we wish to spawn auto type = "calculator"; // type of the actor we wish to spawn
auto args = make_message(); // arguments to construct the actor auto args = make_message(); // arguments to construct the actor
auto tout = std::chrono::seconds(30); // wait no longer than 30s auto tout = std::chrono::seconds(30); // wait no longer than 30s
auto worker = system.middleman().remote_spawn<calculator>(*node, type, auto worker = system.middleman().remote_spawn<calculator>(*node, type, args,
args, tout); tout);
if (!worker) { if (!worker) {
cerr << "*** remote spawn failed: " cerr << "*** remote spawn failed: " << system.render(worker.error())
<< system.render(worker.error()) << endl; << endl;
return; return;
} }
// start using worker in main loop // start using worker in main loop
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* Basic, non-interactive streaming example for processing integers. * * Basic, non-interactive streaming example for processing integers. *
******************************************************************************/ ******************************************************************************/
// Manual refs: lines 17-46, 48-78, 80-107, 121-125 (Streaming) // Manual refs: lines 17-48, 50-83, 85-114, 128-132 (Streaming)
#include <iostream> #include <iostream>
#include <vector> #include <vector>
...@@ -16,94 +16,101 @@ namespace { ...@@ -16,94 +16,101 @@ namespace {
// 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 {[=](open_atom, int n) { return {
// Produce at least one value. [=](open_atom, int n) {
if (n <= 0) // Produce at least one value.
n = 1; if (n <= 0)
// Create a stream manager for implementing a stream source. The n = 1;
// streaming logic requires three functions: initializer, generator, and // Create a stream manager for implementing a stream source. The
// predicate. // streaming logic requires three functions: initializer, generator, and
return attach_stream_source( // predicate.
self, return attach_stream_source(
// Initializer. The type of the first argument (state) is freely self,
// chosen. If no state is required, `caf::unit_t` can be used here. // Initializer. The type of the first argument (state) is freely
[](int& x) { x = 0; }, // chosen. If no state is required, `caf::unit_t` can be used here.
// Generator. This function is called by CAF to produce new stream [](int& x) { x = 0; },
// elements for downstream actors. The `x` argument is our state again // Generator. This function is called by CAF to produce new stream
// (with our freely chosen type). The second argument `out` points to // elements for downstream actors. The `x` argument is our state again
// the output buffer. The template argument (here: int) determines what // (with our freely chosen type). The second argument `out` points to
// elements downstream actors receive in this stream. Finally, `num` is // the output buffer. The template argument (here: int) determines what
// a hint from CAF how many elements we should ideally insert into // elements downstream actors receive in this stream. Finally, `num` is
// `out`. We can always insert fewer or more items. // a hint from CAF how many elements we should ideally insert into
[n](int& x, downstream<int>& out, size_t num) { // `out`. We can always insert fewer or more items.
auto max_x = std::min(x + static_cast<int>(num), n); [n](int& x, downstream<int>& out, size_t num) {
for (; x < max_x; ++x) auto max_x = std::min(x + static_cast<int>(num), n);
out.push(x); for (; x < max_x; ++x)
}, out.push(x);
// Predicate. This function tells CAF when we reached the end. },
[n](const int& x) { return x == n; }); // Predicate. This function tells CAF when we reached the end.
}}; [n](const int& x) { return x == n; });
},
};
} }
// 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 {[=](stream<int> in) { return {
// Create a stream manager for implementing a stream stage. Similar to [=](stream<int> in) {
// `make_source`, we need three functions: initialzer, processor, and // Create a stream manager for implementing a stream stage. Similar to
// finalizer. // `make_source`, we need three functions: initialzer, processor, and
return attach_stream_stage( // finalizer.
self, return attach_stream_stage(
// Our input source. self,
in, // Our input source.
// Initializer. Here, we don't need any state and simply use unit_t. in,
[](unit_t&) { // Initializer. Here, we don't need any state and simply use unit_t.
// nop [](unit_t&) {
}, // nop
// Processor. This function takes individual input elements as `val` },
// and forwards even integers to `out`. // Processor. This function takes individual input elements as `val`
[](unit_t&, downstream<int>& out, int val) { // and forwards even integers to `out`.
if (val % 2 == 0) [](unit_t&, downstream<int>& out, int val) {
out.push(val); if (val % 2 == 0)
}, out.push(val);
// Finalizer. Allows us to run cleanup code once the stream terminates. },
[=](unit_t&, const error& err) { // Finalizer. Allows us to run cleanup code once the stream terminates.
if (err) { [=](unit_t&, const error& err) {
aout(self) << "int_selector aborted with error: " << err << std::endl; if (err) {
} else { aout(self) << "int_selector aborted with error: " << err
aout(self) << "int_selector finalized" << std::endl; << std::endl;
} } else {
// else: regular stream shutdown aout(self) << "int_selector finalized" << std::endl;
}); }
}}; // else: regular stream shutdown
});
},
};
} }
behavior int_sink(event_based_actor* self) { behavior int_sink(event_based_actor* self) {
return {[=](stream<int> in) { return {
// Create a stream manager for implementing a stream sink. Once more, we [=](stream<int> in) {
// have to provide three functions: Initializer, Consumer, Finalizer. // Create a stream manager for implementing a stream sink. Once more, we
return attach_stream_sink( // have to provide three functions: Initializer, Consumer, Finalizer.
self, return attach_stream_sink(
// Our input source. self,
in, // Our input source.
// Initializer. Here, we store all values we receive. Note that streams in,
// are potentially unbound, so this is usually a bad idea outside small // Initializer. Here, we store all values we receive. Note that streams
// examples like this one. // are potentially unbound, so this is usually a bad idea outside small
[](std::vector<int>&) { // examples like this one.
// nop [](std::vector<int>&) {
}, // nop
// Consumer. Takes individual input elements as `val` and stores them },
// in our history. // Consumer. Takes individual input elements as `val` and stores them
[](std::vector<int>& xs, int val) { xs.emplace_back(val); }, // in our history.
// Finalizer. Allows us to run cleanup code once the stream terminates. [](std::vector<int>& xs, int val) { xs.emplace_back(val); },
[=](std::vector<int>& xs, const error& err) { // Finalizer. Allows us to run cleanup code once the stream terminates.
if (err) { [=](std::vector<int>& xs, const error& err) {
aout(self) << "int_sink aborted with error: " << err << std::endl; if (err) {
} else { aout(self) << "int_sink aborted with error: " << err << std::endl;
aout(self) << "int_sink finalized after receiving: " << xs } else {
<< std::endl; aout(self) << "int_sink finalized after receiving: " << xs
} << std::endl;
}); }
}}; });
},
};
} }
struct config : actor_system_config { struct config : actor_system_config {
...@@ -122,7 +129,7 @@ void caf_main(actor_system& sys, const config& cfg) { ...@@ -122,7 +129,7 @@ void caf_main(actor_system& sys, const config& cfg) {
auto snk = sys.spawn(int_sink); auto snk = sys.spawn(int_sink);
auto pipeline = cfg.with_stage ? snk * sys.spawn(int_selector) * src auto pipeline = cfg.with_stage ? snk * sys.spawn(int_selector) * src
: snk * src; : snk * src;
anon_send(pipeline, open_atom::value, cfg.n); anon_send(pipeline, open_atom_v, cfg.n);
} }
} // namespace } // namespace
......
// Manual refs: lines 12-65 (Testing) // Manual refs: lines 12-60 (Testing)
#define CAF_SUITE ping_pong #define CAF_SUITE ping_pong
...@@ -11,24 +11,19 @@ using namespace caf; ...@@ -11,24 +11,19 @@ using namespace caf;
namespace { namespace {
using ping_atom = atom_constant<atom("ping")>;
using pong_atom = atom_constant<atom("pong")>;
behavior ping(event_based_actor* self, actor pong_actor, int n) { behavior ping(event_based_actor* self, actor pong_actor, int n) {
self->send(pong_actor, ping_atom::value, n); self->send(pong_actor, ping_atom_v, n);
return { return {
[=](pong_atom, int x) { [=](pong_atom, int x) {
if (x > 1) if (x > 1)
self->send(pong_actor, ping_atom::value, x - 1); self->send(pong_actor, ping_atom_v, x - 1);
} },
}; };
} }
behavior pong() { behavior pong() {
return { return {
[=](ping_atom, int x) { [=](ping_atom, int x) { return std::make_tuple(pong_atom_v, x); },
return std::make_tuple(pong_atom::value, x);
}
}; };
} }
......
...@@ -39,7 +39,6 @@ set(CAF_CORE_SOURCES ...@@ -39,7 +39,6 @@ set(CAF_CORE_SOURCES
src/actor_registry.cpp src/actor_registry.cpp
src/actor_system.cpp src/actor_system.cpp
src/actor_system_config.cpp src/actor_system_config.cpp
src/atom.cpp
src/attachable.cpp src/attachable.cpp
src/behavior.cpp src/behavior.cpp
src/binary_deserializer.cpp src/binary_deserializer.cpp
...@@ -84,14 +83,12 @@ set(CAF_CORE_SOURCES ...@@ -84,14 +83,12 @@ set(CAF_CORE_SOURCES
src/detail/test_actor_clock.cpp src/detail/test_actor_clock.cpp
src/detail/thread_safe_actor_clock.cpp src/detail/thread_safe_actor_clock.cpp
src/detail/tick_emitter.cpp src/detail/tick_emitter.cpp
src/detail/try_match.cpp
src/detail/uri_impl.cpp src/detail/uri_impl.cpp
src/downstream_manager.cpp src/downstream_manager.cpp
src/downstream_manager_base.cpp src/downstream_manager_base.cpp
src/error.cpp src/error.cpp
src/event_based_actor.cpp src/event_based_actor.cpp
src/execution_unit.cpp src/execution_unit.cpp
src/exit_reason.cpp
src/exit_reason_strings.cpp src/exit_reason_strings.cpp
src/forwarding_actor_proxy.cpp src/forwarding_actor_proxy.cpp
src/group.cpp src/group.cpp
...@@ -121,7 +118,6 @@ set(CAF_CORE_SOURCES ...@@ -121,7 +118,6 @@ set(CAF_CORE_SOURCES
src/monitorable_actor.cpp src/monitorable_actor.cpp
src/node_id.cpp src/node_id.cpp
src/outbound_path.cpp src/outbound_path.cpp
src/pec.cpp
src/pec_strings.cpp src/pec_strings.cpp
src/policy/downstream_messages.cpp src/policy/downstream_messages.cpp
src/policy/unprofiled.cpp src/policy/unprofiled.cpp
...@@ -135,13 +131,11 @@ set(CAF_CORE_SOURCES ...@@ -135,13 +131,11 @@ set(CAF_CORE_SOURCES
src/response_promise.cpp src/response_promise.cpp
src/resumable.cpp src/resumable.cpp
src/rtti_pair.cpp src/rtti_pair.cpp
src/runtime_settings_map.cpp
src/scheduled_actor.cpp src/scheduled_actor.cpp
src/scheduler/abstract_coordinator.cpp src/scheduler/abstract_coordinator.cpp
src/scheduler/test_coordinator.cpp src/scheduler/test_coordinator.cpp
src/scoped_actor.cpp src/scoped_actor.cpp
src/scoped_execution_unit.cpp src/scoped_execution_unit.cpp
src/sec.cpp
src/sec_strings.cpp src/sec_strings.cpp
src/serializer.cpp src/serializer.cpp
src/settings.cpp src/settings.cpp
...@@ -177,7 +171,6 @@ set(CAF_CORE_TEST_SOURCES ...@@ -177,7 +171,6 @@ set(CAF_CORE_TEST_SOURCES
test/actor_system_config.cpp test/actor_system_config.cpp
test/actor_termination.cpp test/actor_termination.cpp
test/aout.cpp test/aout.cpp
test/atom.cpp
test/behavior.cpp test/behavior.cpp
test/binary_deserializer.cpp test/binary_deserializer.cpp
test/binary_serializer.cpp test/binary_serializer.cpp
...@@ -201,7 +194,6 @@ set(CAF_CORE_TEST_SOURCES ...@@ -201,7 +194,6 @@ set(CAF_CORE_TEST_SOURCES
test/detail/ini_consumer.cpp test/detail/ini_consumer.cpp
test/detail/limited_vector.cpp test/detail/limited_vector.cpp
test/detail/parse.cpp test/detail/parse.cpp
test/detail/parser/read_atom.cpp
test/detail/parser/read_bool.cpp test/detail/parser/read_bool.cpp
test/detail/parser/read_floating_point.cpp test/detail/parser/read_floating_point.cpp
test/detail/parser/read_ini.cpp test/detail/parser/read_ini.cpp
...@@ -262,9 +254,7 @@ set(CAF_CORE_TEST_SOURCES ...@@ -262,9 +254,7 @@ set(CAF_CORE_TEST_SOURCES
test/request_timeout.cpp test/request_timeout.cpp
test/result.cpp test/result.cpp
test/rtti_pair.cpp test/rtti_pair.cpp
test/runtime_settings_map.cpp
test/selective_streaming.cpp test/selective_streaming.cpp
test/serial_reply.cpp
test/serialization.cpp test/serialization.cpp
test/settings.cpp test/settings.cpp
test/simple_timeout.cpp test/simple_timeout.cpp
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#pragma once #pragma once
#include <chrono> #include <chrono>
#include <string>
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
...@@ -36,7 +37,7 @@ public: ...@@ -36,7 +37,7 @@ public:
/// Discrete point in time. /// Discrete point in time.
using time_point = typename clock_type::time_point; using time_point = typename clock_type::time_point;
/// Difference between two points in time. /// Time interval.
using duration_type = typename clock_type::duration; using duration_type = typename clock_type::duration;
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
...@@ -48,21 +49,15 @@ public: ...@@ -48,21 +49,15 @@ public:
/// Returns the current wall-clock time. /// Returns the current wall-clock time.
virtual time_point now() const noexcept; virtual time_point now() const noexcept;
/// Returns the difference between `t0` and `t1`, allowing the clock to
/// return an arbitrary value depending on the measurement that took place
/// and the units measured.
virtual duration_type difference(atom_value measurement, long units,
time_point t0, time_point t1) const noexcept;
/// Schedules a `timeout_msg` for `self` at time point `t`, overriding any /// Schedules a `timeout_msg` for `self` at time point `t`, overriding any
/// previous receive timeout. /// previous receive timeout.
virtual void set_ordinary_timeout(time_point t, abstract_actor* self, virtual void set_ordinary_timeout(time_point t, abstract_actor* self,
atom_value type, uint64_t id) std::string type, uint64_t id)
= 0; = 0;
/// Schedules a `timeout_msg` for `self` at time point `t`. /// Schedules a `timeout_msg` for `self` at time point `t`.
virtual void set_multi_timeout(time_point t, abstract_actor* self, virtual void set_multi_timeout(time_point t, abstract_actor* self,
atom_value type, uint64_t id) std::string type, uint64_t id)
= 0; = 0;
/// Schedules a `sec::request_timeout` for `self` at time point `t`. /// Schedules a `sec::request_timeout` for `self` at time point `t`.
...@@ -71,7 +66,7 @@ public: ...@@ -71,7 +66,7 @@ public:
= 0; = 0;
/// Cancels a pending receive timeout. /// Cancels a pending receive timeout.
virtual void cancel_ordinary_timeout(abstract_actor* self, atom_value type) virtual void cancel_ordinary_timeout(abstract_actor* self, std::string type)
= 0; = 0;
/// Cancels the pending request timeout for `id`. /// Cancels the pending request timeout for `id`.
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <condition_variable> #include <condition_variable>
#include <cstdint> #include <cstdint>
#include <mutex> #include <mutex>
#include <string>
#include <thread> #include <thread>
#include <unordered_map> #include <unordered_map>
...@@ -35,12 +36,12 @@ ...@@ -35,12 +36,12 @@
namespace caf { namespace caf {
/// A registry is used to associate actors to IDs or atoms (names). This /// A registry is used to associate actors to IDs or names. This allows a
/// allows a middleman to lookup actor handles after receiving actor IDs /// middleman to lookup actor handles after receiving actor IDs via the network
/// via the network and enables developers to use well-known names to /// and enables developers to use well-known names to identify important actors
/// identify important actors independent from their ID at runtime. /// independent from their ID at runtime. Note that the registry does *not*
/// Note that the registry does *not* contain all actors of an actor system. /// contain all actors of an actor system. The middleman registers actors as
/// The middleman registers actors as needed. /// needed.
class CAF_CORE_EXPORT actor_registry { class CAF_CORE_EXPORT actor_registry {
public: public:
friend class actor_system; friend class actor_system;
...@@ -78,22 +79,22 @@ public: ...@@ -78,22 +79,22 @@ public:
/// Returns the actor associated with `key` or `invalid_actor`. /// Returns the actor associated with `key` or `invalid_actor`.
template <class T = strong_actor_ptr> template <class T = strong_actor_ptr>
T get(atom_value key) const { T get(const std::string& key) const {
return actor_cast<T>(get_impl(key)); return actor_cast<T>(get_impl(key));
} }
/// Associates given actor to `key`. /// Associates given actor to `key`.
template <class T> template <class T>
void put(atom_value key, const T& value) { void put(const std::string& key, const T& value) {
// using reference here and before to allow putting a scoped_actor without // using reference here and before to allow putting a scoped_actor without
// calling .ptr() // calling .ptr()
put_impl(key, actor_cast<strong_actor_ptr>(value)); put_impl(std::move(key), actor_cast<strong_actor_ptr>(value));
} }
/// Removes a name mapping. /// Removes a name mapping.
void erase(atom_value key); void erase(const std::string& key);
using name_map = std::unordered_map<atom_value, strong_actor_ptr>; using name_map = std::unordered_map<std::string, strong_actor_ptr>;
name_map named_actors() const; name_map named_actors() const;
...@@ -111,10 +112,10 @@ private: ...@@ -111,10 +112,10 @@ private:
void put_impl(actor_id key, strong_actor_ptr val); void put_impl(actor_id key, strong_actor_ptr val);
/// Returns the actor associated with `key` or `invalid_actor`. /// Returns the actor associated with `key` or `invalid_actor`.
strong_actor_ptr get_impl(atom_value key) const; strong_actor_ptr get_impl(const std::string& key) const;
/// Associates given actor to `key`. /// Associates given actor to `key`.
void put_impl(atom_value key, strong_actor_ptr value); void put_impl(const std::string& key, strong_actor_ptr value);
using entries = std::unordered_map<actor_id, strong_actor_ptr>; using entries = std::unordered_map<actor_id, strong_actor_ptr>;
......
...@@ -47,7 +47,6 @@ ...@@ -47,7 +47,6 @@
#include "caf/logger.hpp" #include "caf/logger.hpp"
#include "caf/make_actor.hpp" #include "caf/make_actor.hpp"
#include "caf/prohibit_top_level_spawn_marker.hpp" #include "caf/prohibit_top_level_spawn_marker.hpp"
#include "caf/runtime_settings_map.hpp"
#include "caf/scoped_execution_unit.hpp" #include "caf/scoped_execution_unit.hpp"
#include "caf/spawn_options.hpp" #include "caf/spawn_options.hpp"
#include "caf/string_algorithms.hpp" #include "caf/string_algorithms.hpp"
...@@ -68,13 +67,6 @@ struct mpi_field_access { ...@@ -68,13 +67,6 @@ struct mpi_field_access {
} }
}; };
template <atom_value X>
struct mpi_field_access<atom_constant<X>> {
std::string operator()(const uniform_type_info_map&) {
return to_string(X);
}
};
template <> template <>
struct mpi_field_access<void> { struct mpi_field_access<void> {
std::string operator()(const uniform_type_info_map&) { std::string operator()(const uniform_type_info_map&) {
...@@ -123,24 +115,15 @@ public: ...@@ -123,24 +115,15 @@ public:
friend class net::middleman; friend class net::middleman;
friend class abstract_actor; friend class abstract_actor;
/// The number of actors implicitly spawned by the actor system on startup.
static constexpr size_t num_internal_actors = 2;
/// Returns the ID of an internal actor by its name.
/// @pre x in {'SpawnServ', 'ConfigServ', 'StreamServ'}
static constexpr size_t internal_actor_id(atom_value x) {
return x == atom("SpawnServ") ? 0 : (x == atom("ConfigServ") ? 1 : 2);
}
/// Returns the internal actor for dynamic spawn operations. /// Returns the internal actor for dynamic spawn operations.
const strong_actor_ptr& spawn_serv() const { const strong_actor_ptr& spawn_serv() const {
return internal_actors_[internal_actor_id(atom("SpawnServ"))]; return spawn_serv_;
} }
/// Returns the internal actor for storing the runtime configuration /// Returns the internal actor for storing the runtime configuration
/// for this actor system. /// for this actor system.
const strong_actor_ptr& config_serv() const { const strong_actor_ptr& config_serv() const {
return internal_actors_[internal_actor_id(atom("ConfigServ"))]; return config_serv_;
} }
actor_system() = delete; actor_system() = delete;
...@@ -483,16 +466,6 @@ public: ...@@ -483,16 +466,6 @@ public:
/// Returns the system-wide clock. /// Returns the system-wide clock.
actor_clock& clock() noexcept; actor_clock& clock() noexcept;
/// Returns application-specific, system-wide runtime settings.
runtime_settings_map& runtime_settings() {
return settings_;
}
/// Returns application-specific, system-wide runtime settings.
const runtime_settings_map& runtime_settings() const {
return settings_;
}
/// Returns the number of detached actors. /// Returns the number of detached actors.
size_t detached_actors() { size_t detached_actors() {
return detached_.load(); return detached_.load();
...@@ -594,12 +567,12 @@ private: ...@@ -594,12 +567,12 @@ private:
/// Sets the internal actor for dynamic spawn operations. /// Sets the internal actor for dynamic spawn operations.
void spawn_serv(strong_actor_ptr x) { void spawn_serv(strong_actor_ptr x) {
internal_actors_[internal_actor_id(atom("SpawnServ"))] = std::move(x); spawn_serv_ = std::move(x);
} }
/// Sets the internal actor for storing the runtime configuration. /// Sets the internal actor for storing the runtime configuration.
void config_serv(strong_actor_ptr x) { void config_serv(strong_actor_ptr x) {
internal_actors_[internal_actor_id(atom("ConfigServ"))] = std::move(x); config_serv_ = std::move(x);
} }
// -- member variables ------------------------------------------------------- // -- member variables -------------------------------------------------------
...@@ -634,8 +607,11 @@ private: ...@@ -634,8 +607,11 @@ private:
/// Stores whether the system should wait for running actors on shutdown. /// Stores whether the system should wait for running actors on shutdown.
bool await_actors_before_shutdown_; bool await_actors_before_shutdown_;
/// Stores SpawnServ, ConfigServ, and StreamServ. /// Stores config parameters.
std::array<strong_actor_ptr, num_internal_actors> internal_actors_; strong_actor_ptr config_serv_;
/// Allows fully dynamic spawning of actors.
strong_actor_ptr spawn_serv_;
/// Counts the number of detached actors. /// Counts the number of detached actors.
std::atomic<size_t> detached_; std::atomic<size_t> detached_;
...@@ -659,9 +635,6 @@ private: ...@@ -659,9 +635,6 @@ private:
/// Allows waiting on specific values for `logger_dtor_done_`. /// Allows waiting on specific values for `logger_dtor_done_`.
mutable std::condition_variable logger_dtor_cv_; mutable std::condition_variable logger_dtor_cv_;
/// Stores custom, system-wide key-value pairs.
runtime_settings_map settings_;
/// Stores the system-wide factory for deserializing tracing data. /// Stores the system-wide factory for deserializing tracing data.
tracing_data_factory* tracing_context_; tracing_data_factory* tracing_context_;
}; };
......
...@@ -74,10 +74,9 @@ public: ...@@ -74,10 +74,9 @@ public:
using portable_name_map = hash_map<std::type_index, std::string>; using portable_name_map = hash_map<std::type_index, std::string>;
using error_renderer using error_renderer = std::function<std::string(uint8_t, const message&)>;
= std::function<std::string(uint8_t, atom_value, const message&)>;
using error_renderer_map = hash_map<atom_value, error_renderer>; using error_renderer_map = hash_map<uint8_t, error_renderer>;
using group_module_factory = std::function<group_module*()>; using group_module_factory = std::function<group_module*()>;
...@@ -188,15 +187,15 @@ public: ...@@ -188,15 +187,15 @@ public:
/// Enables the actor system to convert errors of this error category /// Enables the actor system to convert errors of this error category
/// to human-readable strings via `renderer`. /// to human-readable strings via `renderer`.
actor_system_config& add_error_category(atom_value x, error_renderer y); actor_system_config& add_error_category(uint8_t category, error_renderer f);
/// Enables the actor system to convert errors of this error category /// Enables the actor system to convert errors of this error category
/// to human-readable strings via `to_string(T)`. /// to human-readable strings via `to_string(T)`.
template <class T> template <class T>
actor_system_config& add_error_category(atom_value category) { actor_system_config&
add_error_category(uint8_t category, string_view category_name) {
auto f = [=](uint8_t val, const std::string& ctx) -> std::string { auto f = [=](uint8_t val, const std::string& ctx) -> std::string {
std::string result; std::string result{category_name.begin(), category_name.end()};
result = to_string(category);
result += ": "; result += ": ";
result += to_string(static_cast<T>(val)); result += to_string(static_cast<T>(val));
if (!ctx.empty()) { if (!ctx.empty()) {
...@@ -206,7 +205,7 @@ public: ...@@ -206,7 +205,7 @@ public:
} }
return result; return result;
}; };
return add_error_category(category, f); return add_error_category(category, error_renderer{f});
} }
/// Loads module `T` with optional template parameters `Ts...`. /// Loads module `T` with optional template parameters `Ts...`.
...@@ -331,11 +330,11 @@ public: ...@@ -331,11 +330,11 @@ public:
static std::string render(const error& err); static std::string render(const error& err);
static std::string render_sec(uint8_t, atom_value, const message&); static std::string render_sec(uint8_t, const message&);
static std::string render_exit_reason(uint8_t, atom_value, const message&); static std::string render_exit_reason(uint8_t, const message&);
static std::string render_pec(uint8_t, atom_value, const message&); static std::string render_pec(uint8_t, const message&);
// -- config file parsing ---------------------------------------------------- // -- config file parsing ----------------------------------------------------
...@@ -422,7 +421,7 @@ CAF_CORE_EXPORT const settings& content(const actor_system_config& cfg); ...@@ -422,7 +421,7 @@ CAF_CORE_EXPORT const settings& content(const actor_system_config& cfg);
/// Tries to retrieve the value associated to `name` from `cfg`. /// Tries to retrieve the value associated to `name` from `cfg`.
/// @relates actor_system_config /// @relates actor_system_config
template <class T> template <class T>
optional<T> get_if(const actor_system_config* cfg, string_view name) { auto get_if(const actor_system_config* cfg, string_view name) {
return get_if<T>(&content(*cfg), name); return get_if<T>(&content(*cfg), name);
} }
......
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
#include "caf/actor_system_config.hpp" #include "caf/actor_system_config.hpp"
#include "caf/actor_traits.hpp" #include "caf/actor_traits.hpp"
#include "caf/after.hpp" #include "caf/after.hpp"
#include "caf/atom.hpp"
#include "caf/attach_continuous_stream_source.hpp" #include "caf/attach_continuous_stream_source.hpp"
#include "caf/attach_continuous_stream_stage.hpp" #include "caf/attach_continuous_stream_stage.hpp"
#include "caf/attach_stream_sink.hpp" #include "caf/attach_stream_sink.hpp"
...@@ -86,7 +85,6 @@ ...@@ -86,7 +85,6 @@
#include "caf/message_priority.hpp" #include "caf/message_priority.hpp"
#include "caf/node_id.hpp" #include "caf/node_id.hpp"
#include "caf/others.hpp" #include "caf/others.hpp"
#include "caf/primitive_variant.hpp"
#include "caf/proxy_registry.hpp" #include "caf/proxy_registry.hpp"
#include "caf/raise_error.hpp" #include "caf/raise_error.hpp"
#include "caf/ref_counted.hpp" #include "caf/ref_counted.hpp"
...@@ -109,6 +107,7 @@ ...@@ -109,6 +107,7 @@
#include "caf/thread_hook.hpp" #include "caf/thread_hook.hpp"
#include "caf/timeout_definition.hpp" #include "caf/timeout_definition.hpp"
#include "caf/to_string.hpp" #include "caf/to_string.hpp"
#include "caf/type_nr.hpp"
#include "caf/typed_actor.hpp" #include "caf/typed_actor.hpp"
#include "caf/typed_actor_pointer.hpp" #include "caf/typed_actor_pointer.hpp"
#include "caf/typed_actor_view.hpp" #include "caf/typed_actor_view.hpp"
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <functional>
#include <iosfwd>
#include <string>
#include <type_traits>
#include "caf/detail/atom_val.hpp"
#include "caf/detail/core_export.hpp"
#include "caf/fwd.hpp"
#include "caf/meta/load_callback.hpp"
namespace caf {
/// The value type of atoms.
enum class atom_value : uint64_t {};
/// @relates atom_value
CAF_CORE_EXPORT std::string to_string(atom_value x);
/// @relates atom_value
CAF_CORE_EXPORT std::ostream& operator<<(std::ostream& out, atom_value x);
/// @relates atom_value
CAF_CORE_EXPORT atom_value to_lowercase(atom_value x);
/// @relates atom_value
CAF_CORE_EXPORT atom_value atom_from_string(string_view x);
/// @relates atom_value
CAF_CORE_EXPORT int compare(atom_value x, atom_value y);
/// Creates an atom from given string literal.
template <size_t Size>
constexpr atom_value atom(char const (&str)[Size]) {
// last character is the NULL terminator
static_assert(Size <= 11, "only 10 characters are allowed");
return static_cast<atom_value>(detail::atom_val(str));
}
/// Creates an atom from given string literal and return an integer
/// representation of the atom..
template <size_t Size>
constexpr uint64_t atom_uint(char const (&str)[Size]) {
static_assert(Size <= 11, "only 10 characters are allowed");
return detail::atom_val(str);
}
/// Converts an atom to its integer representation.
constexpr uint64_t atom_uint(atom_value x) {
return static_cast<uint64_t>(x);
}
/// Lifts an `atom_value` to a compile-time constant.
template <atom_value V>
struct atom_constant {
constexpr atom_constant() {
// nop
}
/// Returns the wrapped value.
constexpr operator atom_value() const {
return V;
}
/// Returns the wrapped value as its base type.
static constexpr uint64_t uint_value() {
return static_cast<uint64_t>(V);
}
/// Returns the wrapped value.
static constexpr atom_value get_value() {
return V;
}
/// Returns an instance *of this constant* (*not* an `atom_value`).
static const atom_constant value;
};
template <class T>
struct is_atom_constant {
static constexpr bool value = false;
};
template <atom_value X>
struct is_atom_constant<atom_constant<X>> {
static constexpr bool value = true;
};
template <atom_value V>
std::string to_string(const atom_constant<V>&) {
return to_string(V);
}
template <atom_value V>
const atom_constant<V> atom_constant<V>::value = atom_constant<V>{};
/// Used for request operations.
using add_atom = atom_constant<atom("add")>;
/// Used for request operations.
using get_atom = atom_constant<atom("get")>;
/// Used for request operations.
using put_atom = atom_constant<atom("put")>;
/// Used for signalizing resolved paths.
using resolve_atom = atom_constant<atom("resolve")>;
/// Used for signalizing updates, e.g., in a key-value store.
using update_atom = atom_constant<atom("update")>;
/// Used for request operations.
using delete_atom = atom_constant<atom("delete")>;
/// Used for response messages.
using ok_atom = atom_constant<atom("ok")>;
/// Used for triggering system-level message handling.
using sys_atom = atom_constant<atom("sys")>;
/// Used for signaling group subscriptions.
using join_atom = atom_constant<atom("join")>;
/// Used for signaling group unsubscriptions.
using leave_atom = atom_constant<atom("leave")>;
/// Used for signaling forwarding paths.
using forward_atom = atom_constant<atom("forward")>;
/// Used for buffer management.
using flush_atom = atom_constant<atom("flush")>;
/// Used for I/O redirection.
using redirect_atom = atom_constant<atom("redirect")>;
/// Used for link requests over network.
using link_atom = atom_constant<atom("link")>;
/// Used for removing networked links.
using unlink_atom = atom_constant<atom("unlink")>;
/// Used for monitor requests over network.
using monitor_atom = atom_constant<atom("monitor")>;
/// Used for removing networked monitors.
using demonitor_atom = atom_constant<atom("demonitor")>;
/// Used for publishing actors at a given port.
using publish_atom = atom_constant<atom("publish")>;
/// Used for publishing actors at a given port.
using publish_udp_atom = atom_constant<atom("pub_udp")>;
/// Used for removing an actor/port mapping.
using unpublish_atom = atom_constant<atom("unpublish")>;
/// Used for removing an actor/port mapping.
using unpublish_udp_atom = atom_constant<atom("unpub_udp")>;
/// Used for signalizing group membership.
using subscribe_atom = atom_constant<atom("subscribe")>;
/// Used for withdrawing group membership.
using unsubscribe_atom = atom_constant<atom("unsubscrib")>;
/// Used for establishing network connections.
using connect_atom = atom_constant<atom("connect")>;
/// Used for contacting a remote UDP endpoint
using contact_atom = atom_constant<atom("contact")>;
/// Used for opening ports or files.
using open_atom = atom_constant<atom("open")>;
/// Used for closing ports or files.
using close_atom = atom_constant<atom("close")>;
/// Used for spawning remote actors.
using spawn_atom = atom_constant<atom("spawn")>;
/// Used for migrating actors to other nodes.
using migrate_atom = atom_constant<atom("migrate")>;
/// Used for triggering periodic operations.
using tick_atom = atom_constant<atom("tick")>;
/// Used for pending out of order messages.
using pending_atom = atom_constant<atom("pending")>;
/// Used as timeout type for `timeout_msg`.
using receive_atom = atom_constant<atom("receive")>;
/// Used as timeout type for `timeout_msg`.
using stream_atom = atom_constant<atom("stream")>;
} // namespace caf
namespace std {
template <>
struct hash<caf::atom_value> {
size_t operator()(caf::atom_value x) const {
hash<uint64_t> f;
return f(static_cast<uint64_t>(x));
}
};
} // namespace std
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
#include "caf/policy/upstream_messages.hpp" #include "caf/policy/upstream_messages.hpp"
#include "caf/policy/urgent_messages.hpp" #include "caf/policy/urgent_messages.hpp"
#include "caf/send.hpp" #include "caf/send.hpp"
#include "caf/type_nr.hpp"
#include "caf/typed_actor.hpp" #include "caf/typed_actor.hpp"
namespace caf { namespace caf {
...@@ -331,7 +332,6 @@ public: ...@@ -331,7 +332,6 @@ public:
/// Blocks this actor until all `xs...` have terminated. /// Blocks this actor until all `xs...` have terminated.
template <class... Ts> template <class... Ts>
void wait_for(Ts&&... xs) { void wait_for(Ts&&... xs) {
using wait_for_atom = atom_constant<atom("waitFor")>;
size_t expected = 0; size_t expected = 0;
size_t i = 0; size_t i = 0;
size_t attach_results[] = {attach_functor(xs)...}; size_t attach_results[] = {attach_functor(xs)...};
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#include <type_traits> #include <type_traits>
#include <vector> #include <vector>
#include "caf/atom.hpp"
#include "caf/detail/bounds_checker.hpp" #include "caf/detail/bounds_checker.hpp"
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/detail/move_if_not_ptr.hpp" #include "caf/detail/move_if_not_ptr.hpp"
...@@ -62,8 +61,6 @@ public: ...@@ -62,8 +61,6 @@ public:
using real = double; using real = double;
using atom = atom_value;
using timespan = caf::timespan; using timespan = caf::timespan;
using string = std::string; using string = std::string;
...@@ -72,8 +69,8 @@ public: ...@@ -72,8 +69,8 @@ public:
using dictionary = caf::dictionary<config_value>; using dictionary = caf::dictionary<config_value>;
using types = detail::type_list<integer, boolean, real, atom, timespan, uri, using types = detail::type_list<integer, boolean, real, timespan, uri, string,
string, list, dictionary>; list, dictionary>;
using variant_type = detail::tl_apply_t<types, variant>; using variant_type = detail::tl_apply_t<types, variant>;
...@@ -176,8 +173,8 @@ private: ...@@ -176,8 +173,8 @@ private:
} }
template <class T> template <class T>
detail::enable_if_t<detail::is_one_of<T, real, atom, timespan, uri, string, detail::enable_if_t<
list, dictionary>::value> detail::is_one_of<T, real, timespan, uri, string, list, dictionary>::value>
set(T x) { set(T x) {
data_ = std::move(x); data_ = std::move(x);
} }
...@@ -259,7 +256,6 @@ struct config_value_access : config_value_access_unspecialized {}; ...@@ -259,7 +256,6 @@ struct config_value_access : config_value_access_unspecialized {};
CAF_DEFAULT_CONFIG_VALUE_ACCESS(bool, "boolean"); CAF_DEFAULT_CONFIG_VALUE_ACCESS(bool, "boolean");
CAF_DEFAULT_CONFIG_VALUE_ACCESS(double, "real64"); CAF_DEFAULT_CONFIG_VALUE_ACCESS(double, "real64");
CAF_DEFAULT_CONFIG_VALUE_ACCESS(atom_value, "atom");
CAF_DEFAULT_CONFIG_VALUE_ACCESS(timespan, "timespan"); CAF_DEFAULT_CONFIG_VALUE_ACCESS(timespan, "timespan");
CAF_DEFAULT_CONFIG_VALUE_ACCESS(uri, "uri"); CAF_DEFAULT_CONFIG_VALUE_ACCESS(uri, "uri");
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "caf/atom.hpp"
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/string_view.hpp" #include "caf/string_view.hpp"
#include "caf/timestamp.hpp" #include "caf/timestamp.hpp"
...@@ -37,7 +36,7 @@ namespace stream { ...@@ -37,7 +36,7 @@ namespace stream {
extern CAF_CORE_EXPORT const timespan desired_batch_complexity; extern CAF_CORE_EXPORT const timespan desired_batch_complexity;
extern CAF_CORE_EXPORT const timespan max_batch_delay; extern CAF_CORE_EXPORT const timespan max_batch_delay;
extern CAF_CORE_EXPORT const timespan credit_round_interval; extern CAF_CORE_EXPORT const timespan credit_round_interval;
extern CAF_CORE_EXPORT const atom_value credit_policy; extern CAF_CORE_EXPORT const string_view credit_policy;
namespace size_policy { namespace size_policy {
...@@ -50,7 +49,7 @@ extern CAF_CORE_EXPORT const int32_t buffer_capacity; ...@@ -50,7 +49,7 @@ extern CAF_CORE_EXPORT const int32_t buffer_capacity;
namespace scheduler { namespace scheduler {
extern CAF_CORE_EXPORT const atom_value policy; extern CAF_CORE_EXPORT const string_view policy;
extern CAF_CORE_EXPORT string_view profiling_output_file; extern CAF_CORE_EXPORT string_view profiling_output_file;
extern CAF_CORE_EXPORT const size_t max_threads; extern CAF_CORE_EXPORT const size_t max_threads;
extern CAF_CORE_EXPORT const size_t max_throughput; extern CAF_CORE_EXPORT const size_t max_throughput;
...@@ -73,19 +72,19 @@ extern CAF_CORE_EXPORT const timespan relaxed_sleep_duration; ...@@ -73,19 +72,19 @@ extern CAF_CORE_EXPORT const timespan relaxed_sleep_duration;
namespace logger { namespace logger {
extern CAF_CORE_EXPORT string_view component_filter; extern CAF_CORE_EXPORT string_view component_filter;
extern CAF_CORE_EXPORT const atom_value console; extern CAF_CORE_EXPORT const string_view console;
extern CAF_CORE_EXPORT string_view console_format; extern CAF_CORE_EXPORT string_view console_format;
extern CAF_CORE_EXPORT const atom_value console_verbosity; extern CAF_CORE_EXPORT const string_view console_verbosity;
extern CAF_CORE_EXPORT string_view file_format; extern CAF_CORE_EXPORT string_view file_format;
extern CAF_CORE_EXPORT string_view file_name; extern CAF_CORE_EXPORT string_view file_name;
extern CAF_CORE_EXPORT const atom_value file_verbosity; extern CAF_CORE_EXPORT const string_view file_verbosity;
} // namespace logger } // namespace logger
namespace middleman { namespace middleman {
extern CAF_CORE_EXPORT std::vector<std::string> app_identifiers; extern CAF_CORE_EXPORT std::vector<std::string> app_identifiers;
extern CAF_CORE_EXPORT const atom_value network_backend; extern CAF_CORE_EXPORT const string_view network_backend;
extern CAF_CORE_EXPORT const size_t max_consecutive_reads; extern CAF_CORE_EXPORT const size_t max_consecutive_reads;
extern CAF_CORE_EXPORT const size_t heartbeat_interval; extern CAF_CORE_EXPORT const size_t heartbeat_interval;
extern CAF_CORE_EXPORT const size_t cached_udp_buffers; extern CAF_CORE_EXPORT const size_t cached_udp_buffers;
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
namespace caf::detail {
namespace {
// clang-format off
// encodes ASCII characters to 6bit encoding
constexpr unsigned char encoding_table[] = {
/* ..0 ..1 ..2 ..3 ..4 ..5 ..6 ..7 ..8 ..9 ..A ..B ..C ..D ..E ..F */
/* 0.. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 1.. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 2.. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 3.. */ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 0, 0, 0, 0,
/* 4.. */ 0, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
/* 5.. */ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 0, 0, 0, 0, 37,
/* 6.. */ 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
/* 7.. */ 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 0, 0, 0, 0};
// clang-format on
// decodes 6bit characters to ASCII
constexpr char decoding_table[] = " 0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ_"
"abcdefghijklmnopqrstuvwxyz";
} // namespace
constexpr uint64_t next_interim(uint64_t current, size_t char_code) {
return (current << 6) | encoding_table[(char_code <= 0x7F) ? char_code : 0];
}
constexpr uint64_t atom_val(const char* cstr, uint64_t interim = 0xF) {
return (*cstr == '\0')
? interim
: atom_val(cstr + 1,
next_interim(interim, static_cast<size_t>(*cstr)));
}
} // namespace caf::detail
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
#include "caf/atom.hpp"
#include "caf/detail/apply_args.hpp" #include "caf/detail/apply_args.hpp"
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/detail/int_list.hpp" #include "caf/detail/int_list.hpp"
...@@ -175,7 +174,7 @@ private: ...@@ -175,7 +174,7 @@ private:
void init(std::integral_constant<size_t, First>, void init(std::integral_constant<size_t, First>,
std::integral_constant<size_t, Last> last) { std::integral_constant<size_t, Last> last) {
auto& element = std::get<First>(cases_); auto& element = std::get<First>(cases_);
arr_[First] = match_case_info{element.type_token(), &element}; arr_[First] = match_case_info{&element};
init(std::integral_constant<size_t, First + 1>{}, last); init(std::integral_constant<size_t, First + 1>{}, last);
} }
......
...@@ -58,8 +58,6 @@ public: ...@@ -58,8 +58,6 @@ public:
size_t size() const noexcept override; size_t size() const noexcept override;
uint32_t type_token() const noexcept override;
rtti_pair type(size_t pos) const noexcept override; rtti_pair type(size_t pos) const noexcept override;
const void* get(size_t pos) const noexcept override; const void* get(size_t pos) const noexcept override;
...@@ -80,7 +78,6 @@ private: ...@@ -80,7 +78,6 @@ private:
// -- data members ----------------------------------------------------------- // -- data members -----------------------------------------------------------
vector_type data_; vector_type data_;
uint32_t type_token_;
size_t size_; size_t size_;
}; };
......
...@@ -60,8 +60,6 @@ public: ...@@ -60,8 +60,6 @@ public:
size_t size() const noexcept override; size_t size() const noexcept override;
uint32_t type_token() const noexcept override;
rtti_pair type(size_t pos) const noexcept override; rtti_pair type(size_t pos) const noexcept override;
const void* get(size_t pos) const noexcept override; const void* get(size_t pos) const noexcept override;
...@@ -91,7 +89,6 @@ private: ...@@ -91,7 +89,6 @@ private:
cow_ptr decorated_; cow_ptr decorated_;
vector_type mapping_; vector_type mapping_;
uint32_t type_token_;
}; };
} // namespace caf::detail } // namespace caf::detail
...@@ -64,8 +64,6 @@ public: ...@@ -64,8 +64,6 @@ public:
size_t size() const noexcept override; size_t size() const noexcept override;
uint32_t type_token() const noexcept override;
rtti_pair type(size_t pos) const noexcept override; rtti_pair type(size_t pos) const noexcept override;
const void* get(size_t pos) const noexcept override; const void* get(size_t pos) const noexcept override;
...@@ -84,13 +82,10 @@ public: ...@@ -84,13 +82,10 @@ public:
void append(type_erased_value_ptr x); void append(type_erased_value_ptr x);
void add_to_type_token(uint16_t typenr);
private: private:
// -- data members ----------------------------------------------------------- // -- data members -----------------------------------------------------------
elements elements_; elements elements_;
uint32_t type_token_;
}; };
CAF_CORE_EXPORT void intrusive_ptr_add_ref(const dynamic_message_data*); CAF_CORE_EXPORT void intrusive_ptr_add_ref(const dynamic_message_data*);
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <cstdint>
#include <map>
#include <string>
#include <vector>
#include "caf/detail/is_one_of.hpp"
#include "caf/timespan.hpp"
// -- forward declarations (this header cannot include fwd.hpp) ----------------
namespace caf {
class config_value;
enum class atom_value : uint64_t;
} // namespace caf
// -- trait --------------------------------------------------------------------
namespace caf::detail {
/// Checks whether `T` is in a primitive value type in `config_value`.
template <class T>
using is_primitive_config_value
= is_one_of<T, int64_t, bool, double, atom_value, timespan, std::string,
std::vector<config_value>, std::map<std::string, config_value>>;
} // namespace caf::detail
...@@ -58,8 +58,6 @@ public: ...@@ -58,8 +58,6 @@ public:
size_t size() const noexcept override; size_t size() const noexcept override;
uint32_t type_token() const noexcept override;
rtti_pair type(size_t pos) const noexcept override; rtti_pair type(size_t pos) const noexcept override;
const void* get(size_t pos) const noexcept override; const void* get(size_t pos) const noexcept override;
...@@ -82,7 +80,6 @@ private: ...@@ -82,7 +80,6 @@ private:
// -- data members ----------------------------------------------------------- // -- data members -----------------------------------------------------------
data_type data_; data_type data_;
uint32_t type_token_;
mapping_type mapping_; mapping_type mapping_;
}; };
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
#include "caf/error.hpp" #include "caf/error.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/make_message.hpp"
#include "caf/message.hpp"
#include "caf/none.hpp" #include "caf/none.hpp"
#include "caf/parser_state.hpp" #include "caf/parser_state.hpp"
#include "caf/string_view.hpp" #include "caf/string_view.hpp"
...@@ -80,8 +82,6 @@ CAF_CORE_EXPORT void parse(string_parser_state& ps, double& x); ...@@ -80,8 +82,6 @@ CAF_CORE_EXPORT void parse(string_parser_state& ps, double& x);
CAF_CORE_EXPORT void parse(string_parser_state& ps, timespan& x); CAF_CORE_EXPORT void parse(string_parser_state& ps, timespan& x);
CAF_CORE_EXPORT void parse(string_parser_state& ps, atom_value& x);
CAF_CORE_EXPORT void parse(string_parser_state& ps, ipv4_address& x); CAF_CORE_EXPORT void parse(string_parser_state& ps, ipv4_address& x);
CAF_CORE_EXPORT void parse(string_parser_state& ps, ipv4_subnet& x); CAF_CORE_EXPORT void parse(string_parser_state& ps, ipv4_subnet& x);
...@@ -193,7 +193,7 @@ error parse(string_view str, T& x) { ...@@ -193,7 +193,7 @@ error parse(string_view str, T& x) {
parse(ps, x); parse(ps, x);
if (ps.code == pec::success) if (ps.code == pec::success)
return none; return none;
return make_error(ps.code, str); return make_error(ps.code, std::string{str.begin(), str.end()});
} }
} // namespace caf::detail } // namespace caf::detail
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <cstdint>
#include <ctype.h>
#include <string>
#include "caf/atom.hpp"
#include "caf/config.hpp"
#include "caf/detail/parser/chars.hpp"
#include "caf/detail/parser/is_char.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/pec.hpp"
CAF_PUSH_UNUSED_LABEL_WARNING
#include "caf/detail/parser/fsm.hpp"
namespace caf::detail::parser {
/// Reads a number, i.e., on success produces either an `int64_t` or a
/// `double`.
template <class State, class Consumer>
void read_atom(State& ps, Consumer&& consumer, bool accept_unquoted = false) {
size_t pos = 0;
char buf[11];
memset(buf, 0, sizeof(buf));
auto is_legal = [](char c) { return isalnum(c) || c == '_' || c == ' '; };
auto is_legal_no_ws = [](char c) { return isalnum(c) || c == '_'; };
auto append = [&](char c) {
if (pos == sizeof(buf) - 1)
return false;
buf[pos++] = c;
return true;
};
auto g = caf::detail::make_scope_guard([&] {
if (ps.code <= pec::trailing_character)
consumer.value(atom(buf));
});
// clang-format off
start();
state(init) {
transition(init, " \t")
transition(read_chars, '\'')
epsilon_if(accept_unquoted, read_unquoted_chars, is_legal)
}
state(read_chars) {
transition(done, '\'')
transition(read_chars, is_legal, append(ch), pec::too_many_characters)
}
term_state(done) {
transition(done, " \t")
}
term_state(read_unquoted_chars) {
transition(read_unquoted_chars, is_legal_no_ws, append(ch), pec::too_many_characters)
}
fin();
// clang-format on
}
} // namespace caf::detail::parser
#include "caf/detail/parser/fsm_undef.hpp"
CAF_POP_WARNINGS
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
#include "caf/config.hpp" #include "caf/config.hpp"
#include "caf/detail/parser/chars.hpp" #include "caf/detail/parser/chars.hpp"
#include "caf/detail/parser/read_atom.hpp"
#include "caf/detail/parser/read_bool.hpp" #include "caf/detail/parser/read_bool.hpp"
#include "caf/detail/parser/read_number_or_timespan.hpp" #include "caf/detail/parser/read_number_or_timespan.hpp"
#include "caf/detail/parser/read_string.hpp" #include "caf/detail/parser/read_string.hpp"
...@@ -190,7 +189,6 @@ void read_ini_value(State& ps, Consumer&& consumer, InsideList inside_list) { ...@@ -190,7 +189,6 @@ void read_ini_value(State& ps, Consumer&& consumer, InsideList inside_list) {
start(); start();
state(init) { state(init) {
fsm_epsilon(read_string(ps, consumer), done, '"') fsm_epsilon(read_string(ps, consumer), done, '"')
fsm_epsilon(read_atom(ps, consumer), done, '\'')
fsm_epsilon(read_number(ps, consumer), done, '.') fsm_epsilon(read_number(ps, consumer), done, '.')
fsm_epsilon(read_bool(ps, consumer), done, "ft") fsm_epsilon(read_bool(ps, consumer), done, "ft")
fsm_epsilon(read_number_or_timespan(ps, consumer, inside_list), fsm_epsilon(read_number_or_timespan(ps, consumer, inside_list),
......
...@@ -99,17 +99,17 @@ public: ...@@ -99,17 +99,17 @@ public:
struct ordinary_timeout final : delayed_event { struct ordinary_timeout final : delayed_event {
static constexpr bool cancellable = true; static constexpr bool cancellable = true;
ordinary_timeout(time_point due, strong_actor_ptr self, atom_value type, ordinary_timeout(time_point due, strong_actor_ptr self, std::string type,
uint64_t id) uint64_t id)
: delayed_event(ordinary_timeout_type, due), : delayed_event(ordinary_timeout_type, due),
self(std::move(self)), self(std::move(self)),
type(type), type(std::move(type)),
id(id) { id(id) {
// nop // nop
} }
strong_actor_ptr self; strong_actor_ptr self;
atom_value type; std::string type;
uint64_t id; uint64_t id;
}; };
...@@ -118,17 +118,17 @@ public: ...@@ -118,17 +118,17 @@ public:
struct multi_timeout final : delayed_event { struct multi_timeout final : delayed_event {
static constexpr bool cancellable = true; static constexpr bool cancellable = true;
multi_timeout(time_point due, strong_actor_ptr self, atom_value type, multi_timeout(time_point due, strong_actor_ptr self, std::string type,
uint64_t id) uint64_t id)
: delayed_event(multi_timeout_type, due), : delayed_event(multi_timeout_type, due),
self(std::move(self)), self(std::move(self)),
type(type), type(std::move(type)),
id(id) { id(id) {
// nop // nop
} }
strong_actor_ptr self; strong_actor_ptr self;
atom_value type; std::string type;
uint64_t id; uint64_t id;
}; };
...@@ -193,24 +193,24 @@ public: ...@@ -193,24 +193,24 @@ public:
/// Cancels matching ordinary timeouts. /// Cancels matching ordinary timeouts.
struct ordinary_timeout_cancellation final : cancellation { struct ordinary_timeout_cancellation final : cancellation {
ordinary_timeout_cancellation(actor_id aid, atom_value type) ordinary_timeout_cancellation(actor_id aid, std::string type)
: cancellation(ordinary_timeout_cancellation_type, aid), type(type) { : cancellation(ordinary_timeout_cancellation_type, aid), type(type) {
// nop // nop
} }
atom_value type; std::string type;
}; };
/// Cancels the matching multi timeout. /// Cancels the matching multi timeout.
struct multi_timeout_cancellation final : cancellation { struct multi_timeout_cancellation final : cancellation {
multi_timeout_cancellation(actor_id aid, atom_value type, uint64_t id) multi_timeout_cancellation(actor_id aid, std::string type, uint64_t id)
: cancellation(ordinary_timeout_cancellation_type, aid), : cancellation(ordinary_timeout_cancellation_type, aid),
type(type), type(std::move(type)),
id(id) { id(id) {
// nop // nop
} }
atom_value type; std::string type;
uint64_t id; uint64_t id;
}; };
...@@ -277,16 +277,16 @@ public: ...@@ -277,16 +277,16 @@ public:
// -- overridden member functions -------------------------------------------- // -- overridden member functions --------------------------------------------
void set_ordinary_timeout(time_point t, abstract_actor* self, atom_value type, void set_ordinary_timeout(time_point t, abstract_actor* self,
uint64_t id) override; std::string type, uint64_t id) override;
void set_multi_timeout(time_point t, abstract_actor* self, atom_value type, void set_multi_timeout(time_point t, abstract_actor* self, std::string type,
uint64_t id) override; uint64_t id) override;
void set_request_timeout(time_point t, abstract_actor* self, void set_request_timeout(time_point t, abstract_actor* self,
message_id id) override; message_id id) override;
void cancel_ordinary_timeout(abstract_actor* self, atom_value type) override; void cancel_ordinary_timeout(abstract_actor* self, std::string type) override;
void cancel_request_timeout(abstract_actor* self, message_id id) override; void cancel_request_timeout(abstract_actor* self, message_id id) override;
......
...@@ -86,73 +86,74 @@ public: ...@@ -86,73 +86,74 @@ public:
/// Prints a separator to the result string. /// Prints a separator to the result string.
void sep(); void sep();
void consume(atom_value x); void consume(const timespan& x);
void consume(string_view str); void consume(const timestamp& x);
void consume(timespan x); void consume(const bool& x);
void consume(timestamp x);
void consume(bool x);
void consume(const void* ptr);
void consume(const char* cstr);
void consume(const std::vector<bool>& xs); void consume(const std::vector<bool>& xs);
template <class T> template <class T, size_t N>
enable_if_t<std::is_floating_point<T>::value> consume(T x) { void consume(const T (&xs)[N]) {
result_ += std::to_string(x); consume_range(xs, xs + N);
}
template <class T>
enable_if_t<std::is_integral<T>::value && std::is_signed<T>::value>
consume(T x) {
consume_int(static_cast<int64_t>(x));
} }
template <class T> template <class T>
enable_if_t<std::is_integral<T>::value && std::is_unsigned<T>::value> void consume(const T& x) {
consume(T x) { if constexpr (std::is_pointer<T>::value) {
consume_int(static_cast<uint64_t>(x)); consume_ptr(x);
} else if constexpr (std::is_convertible<T, string_view>::value) {
consume_str(string_view{x});
} else if constexpr (std::is_integral<T>::value) {
if constexpr (std::is_signed<T>::value)
consume_int(static_cast<int64_t>(x));
else
consume_int(static_cast<uint64_t>(x));
} else if constexpr (std::is_floating_point<T>::value) {
result_ += std::to_string(x);
} else if constexpr (has_to_string<T>::value) {
result_ += to_string(x);
} else if constexpr (is_inspectable<stringification_inspector, T>::value) {
inspect(*this, const_cast<T&>(x));
} else if constexpr (is_map_like<T>::value) {
result_ += '{';
for (const auto& kvp : x) {
sep();
consume(kvp.first);
result_ += " = ";
consume(kvp.second);
}
result_ += '}';
} else if constexpr (is_iterable<T>::value) {
consume_range(x.begin(), x.end());
} else if constexpr (has_peek_all<T>::value) {
result_ += '[';
x.peek_all(*this);
result_ += ']';
} else {
result_ += "<unprintable>";
}
} }
template <class Clock, class Duration> template <class Clock, class Duration>
void consume(std::chrono::time_point<Clock, Duration> x) { void consume(const std::chrono::time_point<Clock, Duration>& x) {
timestamp tmp{std::chrono::duration_cast<timespan>(x.time_since_epoch())}; timestamp tmp{std::chrono::duration_cast<timespan>(x.time_since_epoch())};
consume(tmp); consume(tmp);
} }
template <class Rep, class Period> template <class Rep, class Period>
void consume(std::chrono::duration<Rep, Period> x) { void consume(const std::chrono::duration<Rep, Period>& x) {
auto tmp = std::chrono::duration_cast<timespan>(x); auto tmp = std::chrono::duration_cast<timespan>(x);
consume(tmp); consume(tmp);
} }
// Unwrap std::ref. // Unwrap std::ref.
template <class T> template <class T>
void consume(std::reference_wrapper<T> x) { void consume(const std::reference_wrapper<T>& x) {
return consume(x.get()); return consume(x.get());
} }
/// Picks up user-defined `to_string` functions.
template <class T>
enable_if_t<!std::is_pointer<T>::value && has_to_string<T>::value>
consume(const T& x) {
result_ += to_string(x);
}
/// Delegates to `inspect(*this, x)` if available and `T` does not provide
/// a `to_string` overload.
template <class T>
enable_if_t<is_inspectable<stringification_inspector, T>::value
&& !has_to_string<T>::value>
consume(const T& x) {
inspect(*this, const_cast<T&>(x));
}
template <class F, class S> template <class F, class S>
void consume(const std::pair<F, S>& x) { void consume(const std::pair<F, S>& x) {
result_ += '('; result_ += '(';
...@@ -167,81 +168,6 @@ public: ...@@ -167,81 +168,6 @@ public:
result_ += ')'; result_ += ')';
} }
template <class T>
enable_if_t<is_map_like<T>::value
&& !is_inspectable<stringification_inspector, T>::value
&& !has_to_string<T>::value>
consume(const T& xs) {
result_ += '{';
for (const auto& kvp : xs) {
sep();
consume(kvp.first);
result_ += " = ";
consume(kvp.second);
}
result_ += '}';
}
template <class Iterator>
void consume_range(Iterator first, Iterator last) {
result_ += '[';
while (first != last) {
sep();
consume(*first++);
}
result_ += ']';
}
template <class T>
enable_if_t<is_iterable<T>::value && !is_map_like<T>::value
&& !std::is_convertible<T, string_view>::value
&& !is_inspectable<stringification_inspector, T>::value
&& !has_to_string<T>::value>
consume(const T& xs) {
consume_range(xs.begin(), xs.end());
}
template <class T, size_t S>
void consume(const T (&xs)[S]) {
return consume_range(xs, xs + S);
}
template <class T>
enable_if_t<has_peek_all<T>::value
&& !is_iterable<T>::value // pick begin()/end() over peek_all
&& !is_inspectable<stringification_inspector, T>::value
&& !has_to_string<T>::value>
consume(const T& xs) {
result_ += '[';
xs.peek_all(*this);
result_ += ']';
}
template <class T>
enable_if_t<
std::is_pointer<T>::value
&& !std::is_same<void, typename std::remove_pointer<T>::type>::value>
consume(const T ptr) {
if (ptr) {
result_ += '*';
consume(*ptr);
} else {
result_ += "<null>";
}
}
/// Fallback printing `<unprintable>`.
template <class T>
enable_if_t<!is_iterable<T>::value && !has_peek_all<T>::value
&& !std::is_pointer<T>::value
&& !is_inspectable<stringification_inspector, T>::value
&& !std::is_arithmetic<T>::value
&& !std::is_convertible<T, string_view>::value
&& !has_to_string<T>::value>
consume(const T&) {
result_ += "<unprintable>";
}
void traverse() { void traverse() {
// end of recursion // end of recursion
} }
...@@ -308,6 +234,32 @@ public: ...@@ -308,6 +234,32 @@ public:
} }
private: private:
template <class Iterator>
void consume_range(Iterator first, Iterator last) {
result_ += '[';
while (first != last) {
sep();
consume(*first++);
}
result_ += ']';
}
template <class T>
void consume_ptr(const T* ptr) {
if (ptr) {
result_ += '*';
consume(*ptr);
} else {
result_ += "nullptr";
}
}
void consume_str(string_view str);
void consume_ptr(const void* ptr);
void consume_ptr(const char* cstr);
void consume_int(int64_t x); void consume_int(int64_t x);
void consume_int(uint64_t x); void consume_int(uint64_t x);
......
...@@ -31,9 +31,6 @@ public: ...@@ -31,9 +31,6 @@ public:
time_point now() const noexcept override; time_point now() const noexcept override;
duration_type difference(atom_value measurement, long units, time_point t0,
time_point t1) const noexcept override;
/// Returns whether the actor clock has at least one pending timeout. /// Returns whether the actor clock has at least one pending timeout.
bool has_pending_timeout() const { bool has_pending_timeout() const {
return !schedule_.empty(); return !schedule_.empty();
...@@ -54,12 +51,6 @@ public: ...@@ -54,12 +51,6 @@ public:
/// Advances the time by `x` and dispatches timeouts and delayed messages. /// Advances the time by `x` and dispatches timeouts and delayed messages.
/// @returns The number of triggered timeouts. /// @returns The number of triggered timeouts.
size_t advance_time(duration_type x); size_t advance_time(duration_type x);
/// Configures the returned value for `difference`. For example, inserting
/// `('foo', 120ns)` causes the clock to return `units * 120ns` for any call
/// to `difference` with `measurement == 'foo'` regardless of the time points
/// passed to the function.
std::map<atom_value, duration_type> time_per_unit;
}; };
} // namespace caf::detail } // namespace caf::detail
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <condition_variable> #include <condition_variable>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <string>
#include "caf/abstract_actor.hpp" #include "caf/abstract_actor.hpp"
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
...@@ -43,16 +44,16 @@ public: ...@@ -43,16 +44,16 @@ public:
// -- member functions ------------------------------------------------------- // -- member functions -------------------------------------------------------
void set_ordinary_timeout(time_point t, abstract_actor* self, atom_value type, void set_ordinary_timeout(time_point t, abstract_actor* self,
uint64_t id) override; std::string type, uint64_t id) override;
void set_request_timeout(time_point t, abstract_actor* self, void set_request_timeout(time_point t, abstract_actor* self,
message_id id) override; message_id id) override;
void set_multi_timeout(time_point t, abstract_actor* self, atom_value type, void set_multi_timeout(time_point t, abstract_actor* self, std::string type,
uint64_t id) override; uint64_t id) override;
void cancel_ordinary_timeout(abstract_actor* self, atom_value type) override; void cancel_ordinary_timeout(abstract_actor* self, std::string type) override;
void cancel_request_timeout(abstract_actor* self, message_id id) override; void cancel_request_timeout(abstract_actor* self, message_id id) override;
......
...@@ -19,47 +19,32 @@ ...@@ -19,47 +19,32 @@
#pragma once #pragma once
#include <array> #include <array>
#include <numeric> #include <cstdint>
#include <typeinfo> #include <typeinfo>
#include "caf/atom.hpp"
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/detail/type_list.hpp" #include "caf/detail/type_list.hpp"
#include "caf/fwd.hpp"
#include "caf/type_nr.hpp" #include "caf/type_nr.hpp"
namespace caf::detail { namespace caf::detail {
struct meta_element { struct meta_element {
atom_value v;
uint16_t typenr; uint16_t typenr;
const std::type_info* type; const std::type_info* type;
bool (*fun)(const meta_element&, const type_erased_tuple&, size_t);
}; };
CAF_CORE_EXPORT bool
match_element(const meta_element&, const type_erased_tuple&, size_t);
CAF_CORE_EXPORT bool
match_atom_constant(const meta_element&, const type_erased_tuple&, size_t);
template <class T, uint16_t TN = type_nr<T>::value> template <class T, uint16_t TN = type_nr<T>::value>
struct meta_element_factory { struct meta_element_factory {
static meta_element create() { static meta_element create() {
return {static_cast<atom_value>(0), TN, nullptr, match_element}; return {TN, nullptr};
} }
}; };
template <class T> template <class T>
struct meta_element_factory<T, 0> { struct meta_element_factory<T, 0> {
static meta_element create() { static meta_element create() {
return {static_cast<atom_value>(0), 0, &typeid(T), match_element}; return {0, &typeid(T)};
}
};
template <atom_value V>
struct meta_element_factory<atom_constant<V>, type_nr<atom_value>::value> {
static meta_element create() {
return {V, type_nr<atom_value>::value, nullptr, match_atom_constant};
} }
}; };
...@@ -74,7 +59,4 @@ struct meta_elements<type_list<Ts...>> { ...@@ -74,7 +59,4 @@ struct meta_elements<type_list<Ts...>> {
} }
}; };
CAF_CORE_EXPORT bool
try_match(const type_erased_tuple& xs, const meta_element* iter, size_t ps);
} // namespace caf::detail } // namespace caf::detail
...@@ -141,10 +141,6 @@ public: ...@@ -141,10 +141,6 @@ public:
return dispatch(pos, source); return dispatch(pos, source);
} }
uint32_t type_token() const noexcept override {
return make_type_token<Ts...>();
}
rtti_pair type(size_t pos) const noexcept override { rtti_pair type(size_t pos) const noexcept override {
return types_[pos]; return types_[pos];
} }
......
...@@ -24,15 +24,13 @@ ...@@ -24,15 +24,13 @@
#include <tuple> #include <tuple>
#include <typeinfo> #include <typeinfo>
#include "caf/detail/apply_args.hpp"
#include "caf/error.hpp" #include "caf/error.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/type_erased_tuple.hpp" #include "caf/type_erased_tuple.hpp"
#include "caf/type_erased_value.hpp" #include "caf/type_erased_value.hpp"
#include "caf/type_nr.hpp" #include "caf/type_nr.hpp"
#include "caf/detail/apply_args.hpp"
#include "caf/detail/try_match.hpp"
namespace caf::detail { namespace caf::detail {
template <class... Ts> template <class... Ts>
...@@ -80,10 +78,6 @@ public: ...@@ -80,10 +78,6 @@ public:
return sizeof...(Ts); return sizeof...(Ts);
} }
uint32_t type_token() const noexcept override {
return make_type_token<Ts...>();
}
rtti_pair type(size_t pos) const noexcept override { rtti_pair type(size_t pos) const noexcept override {
return ptrs_[pos]->type(); return ptrs_[pos]->type();
} }
......
...@@ -142,38 +142,16 @@ struct is_duration : std::false_type {}; ...@@ -142,38 +142,16 @@ struct is_duration : std::false_type {};
template <class Period, class Rep> template <class Period, class Rep>
struct is_duration<std::chrono::duration<Period, Rep>> : std::true_type {}; struct is_duration<std::chrono::duration<Period, Rep>> : std::true_type {};
/// Checks whether `T` is considered a builtin type.
///
/// Builtin types are: (1) all arithmetic types (including time types), (2)
/// string types from the STL, and (3) built-in types such as `actor_ptr`.
template <class T>
struct is_builtin {
static constexpr bool value = std::is_arithmetic<T>::value
|| is_duration<T>::value
|| is_one_of<T, timestamp, std::string,
std::u16string, std::u32string,
atom_value, message, actor, group,
node_id>::value;
};
/// Checks whether `T` is primitive, i.e., either an arithmetic type or /// Checks whether `T` is primitive, i.e., either an arithmetic type or
/// convertible to one of STL's string types. /// convertible to one of STL's string types.
template <class T> template <class T>
struct is_primitive { struct is_primitive {
static constexpr bool value = std::is_arithmetic<T>::value static constexpr bool value = std::is_convertible<T, std::string>::value
|| std::is_convertible<T, std::string>::value
|| std::is_convertible<T, std::u16string>::value || std::is_convertible<T, std::u16string>::value
|| std::is_convertible<T, std::u32string>::value || std::is_convertible<T, std::u32string>::value
|| std::is_convertible<T, atom_value>::value; || std::is_arithmetic<T>::value;
}; };
// Workaround for weird GCC 4.8 STL implementation that breaks
// `std::is_convertible<T, atom_value>::value` for tuples containing atom
// constants.
// TODO: remove when dropping support for GCC 4.8.
template <class... Ts>
struct is_primitive<std::tuple<Ts...>> : std::false_type {};
/// Checks whether `T1` is comparable with `T2`. /// Checks whether `T1` is comparable with `T2`.
template <class T1, class T2> template <class T1, class T2>
class is_comparable { class is_comparable {
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#include "caf/actor_addr.hpp" #include "caf/actor_addr.hpp"
#include "caf/actor_control_block.hpp" #include "caf/actor_control_block.hpp"
#include "caf/atom.hpp"
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/detail/type_list.hpp" #include "caf/detail/type_list.hpp"
#include "caf/message.hpp" #include "caf/message.hpp"
......
...@@ -22,42 +22,19 @@ ...@@ -22,42 +22,19 @@
#include <functional> #include <functional>
#include <utility> #include <utility>
#include "caf/atom.hpp"
#include "caf/detail/comparable.hpp" #include "caf/detail/comparable.hpp"
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/error_category.hpp"
#include "caf/error_code.hpp" #include "caf/error_code.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/meta/load_callback.hpp"
#include "caf/meta/omittable_if_empty.hpp" #include "caf/meta/omittable_if_empty.hpp"
#include "caf/meta/save_callback.hpp"
#include "caf/meta/type_name.hpp" #include "caf/meta/type_name.hpp"
#include "caf/none.hpp" #include "caf/none.hpp"
namespace caf { namespace caf {
class error;
/// Evaluates to true if `T` is an enum with a free function
/// `make_error` for converting it to an `error`.
template <class T>
struct has_make_error {
private:
template <class U>
static auto test_make_error(U* x) -> decltype(make_error(*x));
template <class U>
static auto test_make_error(...) -> void;
using type = decltype(test_make_error<T>(nullptr));
public:
static constexpr bool value = std::is_enum<T>::value
&& std::is_same<error, type>::value;
};
/// Convenience alias for `std::enable_if<has_make_error<T>::value, U>::type`.
template <class T, class U = void>
using enable_if_has_make_error_t =
typename std::enable_if<has_make_error<T>::value, U>::type;
/// A serializable type for storing error codes with category and optional, /// A serializable type for storing error codes with category and optional,
/// human-readable context information. Unlike error handling classes from /// human-readable context information. Unlike error handling classes from
/// the C++ standard library, this type is serializable. It consists of an /// the C++ standard library, this type is serializable. It consists of an
...@@ -93,7 +70,7 @@ public: ...@@ -93,7 +70,7 @@ public:
// -- member types ----------------------------------------------------------- // -- member types -----------------------------------------------------------
using inspect_fun using inspect_fun
= std::function<error(meta::type_name_t, uint8_t&, atom_value&, = std::function<error(meta::type_name_t, uint8_t&, uint8_t&,
meta::omittable_if_empty_t, message&)>; meta::omittable_if_empty_t, message&)>;
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
...@@ -110,32 +87,30 @@ public: ...@@ -110,32 +87,30 @@ public:
error& operator=(const error&); error& operator=(const error&);
error(uint8_t x, atom_value y); error(uint8_t x, uint8_t y);
error(uint8_t x, atom_value y, message z); error(uint8_t x, uint8_t y, message z);
template <class E, class = enable_if_has_make_error_t<E>> template <class Enum, uint8_t Category = error_category<Enum>::value>
error(E error_value) : error(make_error(error_value)) { error(Enum error_value) : error(static_cast<uint8_t>(error_value), Category) {
// nop // nop
} }
template <class E> template <class Enum>
error(error_code<E> code) : error(code.value()) { error(error_code<Enum> code) : error(code.value()) {
// nop // nop
} }
template <class E, class = enable_if_has_make_error_t<E>> template <class E>
error& operator=(E error_value) { error& operator=(E error_value) {
auto tmp = make_error(error_value); error tmp{error_value};
std::swap(data_, tmp.data_); std::swap(data_, tmp.data_);
return *this; return *this;
} }
template <class E> template <class E>
error& operator=(error_code<E> code) { error& operator=(error_code<E> code) {
auto tmp = make_error(code.value()); return *this = code.value();
std::swap(data_, tmp.data_);
return *this;
} }
~error(); ~error();
...@@ -148,7 +123,7 @@ public: ...@@ -148,7 +123,7 @@ public:
/// Returns the category of this error. /// Returns the category of this error.
/// @pre `*this != none` /// @pre `*this != none`
atom_value category() const noexcept; uint8_t category() const noexcept;
/// Returns context information to this error. /// Returns context information to this error.
/// @pre `*this != none` /// @pre `*this != none`
...@@ -166,7 +141,7 @@ public: ...@@ -166,7 +141,7 @@ public:
int compare(const error&) const noexcept; int compare(const error&) const noexcept;
int compare(uint8_t x, atom_value y) const noexcept; int compare(uint8_t x, uint8_t y) const noexcept;
// -- modifiers -------------------------------------------------------------- // -- modifiers --------------------------------------------------------------
...@@ -227,7 +202,7 @@ private: ...@@ -227,7 +202,7 @@ private:
uint8_t& code_ref() noexcept; uint8_t& code_ref() noexcept;
atom_value& category_ref() noexcept; uint8_t& category_ref() noexcept;
void init(); void init();
...@@ -243,6 +218,19 @@ private: ...@@ -243,6 +218,19 @@ private:
/// @relates error /// @relates error
CAF_CORE_EXPORT std::string to_string(const error& x); CAF_CORE_EXPORT std::string to_string(const error& x);
/// @relates error
template <class Enum>
error make_error(Enum code) {
return error{static_cast<uint8_t>(code), error_category<Enum>::value};
}
/// @relates error
template <class Enum, class T, class... Ts>
error make_error(Enum code, T&& x, Ts&&... xs) {
return error{static_cast<uint8_t>(code), error_category<Enum>::value,
make_message(std::forward<T>(x), std::forward<Ts>(xs)...)};
}
/// @relates error /// @relates error
inline bool operator==(const error& x, none_t) { inline bool operator==(const error& x, none_t) {
return !x; return !x;
...@@ -254,15 +242,16 @@ inline bool operator==(none_t, const error& x) { ...@@ -254,15 +242,16 @@ inline bool operator==(none_t, const error& x) {
} }
/// @relates error /// @relates error
template <class E, class = enable_if_has_make_error_t<E>> template <class Enum, uint8_t Category = error_category<Enum>::value>
bool operator==(const error& x, E y) { bool operator==(const error& x, Enum y) {
return x == make_error(y); auto code = static_cast<uint8_t>(y);
return code == 0 ? !x : x && x.category() == Category && x.code() == code;
} }
/// @relates error /// @relates error
template <class E, class = enable_if_has_make_error_t<E>> template <class Enum, uint8_t Category = error_category<Enum>::value>
bool operator==(E x, const error& y) { bool operator==(Enum x, const error& y) {
return make_error(x) == y; return y == x;
} }
/// @relates error /// @relates error
...@@ -276,14 +265,14 @@ inline bool operator!=(none_t, const error& x) { ...@@ -276,14 +265,14 @@ inline bool operator!=(none_t, const error& x) {
} }
/// @relates error /// @relates error
template <class E, class = enable_if_has_make_error_t<E>> template <class Enum, uint8_t Category = error_category<Enum>::value>
bool operator!=(const error& x, E y) { bool operator!=(const error& x, Enum y) {
return !(x == y); return !(x == y);
} }
/// @relates error /// @relates error
template <class E, class = enable_if_has_make_error_t<E>> template <class Enum, uint8_t Category = error_category<Enum>::value>
bool operator!=(E x, const error& y) { bool operator!=(Enum x, const error& y) {
return !(x == y); return !(x == y);
} }
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* | |___ / ___ \| _| Framework * * | |___ / ___ \| _| Framework *
* \____/_/ \_|_| * * \____/_/ \_|_| *
* * * *
* Copyright 2011-2018 Dominik Charousset * * Copyright 2011-2019 Dominik Charousset *
* * * *
* Distributed under the terms and conditions of the BSD 3-Clause License or * * Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software * * (at your option) under the terms and conditions of the Boost Software *
...@@ -16,18 +16,14 @@ ...@@ -16,18 +16,14 @@
* http://www.boost.org/LICENSE_1_0.txt. * * http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/ ******************************************************************************/
#include "caf/exit_reason.hpp" #pragma once
#include "caf/message.hpp" #include <cstdint>
namespace caf { namespace caf {
error make_error(exit_reason x) { /// Customization point for enabling conversion from an enum type to an ::error.
return {static_cast<uint8_t>(x), atom("exit")}; template <class T>
} struct error_category;
error make_error(exit_reason x, message context) {
return {static_cast<uint8_t>(x), atom("exit"), std::move(context)};
}
} // namespace caf } // namespace caf
...@@ -22,10 +22,11 @@ ...@@ -22,10 +22,11 @@
#pragma once #pragma once
#include <cstdint>
#include <string> #include <string>
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/error.hpp" #include "caf/error_category.hpp"
namespace caf { namespace caf {
...@@ -54,7 +55,9 @@ enum class exit_reason : uint8_t { ...@@ -54,7 +55,9 @@ enum class exit_reason : uint8_t {
/// Returns a string representation of given exit reason. /// Returns a string representation of given exit reason.
CAF_CORE_EXPORT std::string to_string(exit_reason); CAF_CORE_EXPORT std::string to_string(exit_reason);
/// @relates exit_reason template <>
CAF_CORE_EXPORT error make_error(exit_reason); struct error_category<exit_reason> {
static constexpr uint8_t value = 3;
};
} // namespace caf } // namespace caf
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "caf/deep_to_string.hpp" #include "caf/deep_to_string.hpp"
#include "caf/error.hpp" #include "caf/error.hpp"
#include "caf/error_category.hpp"
#include "caf/unifyn.hpp" #include "caf/unifyn.hpp"
#include "caf/unit.hpp" #include "caf/unit.hpp"
...@@ -92,8 +93,8 @@ public: ...@@ -92,8 +93,8 @@ public:
construct(other); construct(other);
} }
template <class Code, class E = enable_if_has_make_error_t<Code>> template <class Enum, uint8_t Category = error_category<Enum>::value>
expected(Code code) : engaged_(false) { expected(Enum code) : engaged_(false) {
new (std::addressof(error_)) caf::error(make_error(code)); new (std::addressof(error_)) caf::error(make_error(code));
} }
...@@ -168,8 +169,8 @@ public: ...@@ -168,8 +169,8 @@ public:
return *this; return *this;
} }
template <class Code> template <class Enum, uint8_t Category = error_category<Enum>::value>
enable_if_has_make_error_t<Code, expected&> operator=(Code code) { expected& operator=(Enum code) {
return *this = make_error(code); return *this = make_error(code);
} }
...@@ -309,14 +310,14 @@ bool operator==(const error& x, const expected<T>& y) { ...@@ -309,14 +310,14 @@ bool operator==(const error& x, const expected<T>& y) {
} }
/// @relates expected /// @relates expected
template <class T, class E> template <class T, class Enum, uint8_t = error_category<Enum>::value>
enable_if_has_make_error_t<E, bool> operator==(const expected<T>& x, E y) { bool operator==(const expected<T>& x, Enum y) {
return x == make_error(y); return x == make_error(y);
} }
/// @relates expected /// @relates expected
template <class T, class E> template <class Enum, class T, uint8_t = error_category<Enum>::value>
enable_if_has_make_error_t<E, bool> operator==(E x, const expected<T>& y) { bool operator==(Enum x, const expected<T>& y) {
return y == make_error(x); return y == make_error(x);
} }
...@@ -352,14 +353,14 @@ bool operator!=(const error& x, const expected<T>& y) { ...@@ -352,14 +353,14 @@ bool operator!=(const error& x, const expected<T>& y) {
} }
/// @relates expected /// @relates expected
template <class T, class E> template <class T, class Enum, uint8_t = error_category<Enum>::value>
enable_if_has_make_error_t<E, bool> operator!=(const expected<T>& x, E y) { bool operator!=(const expected<T>& x, Enum y) {
return !(x == y); return !(x == y);
} }
/// @relates expected /// @relates expected
template <class T, class E> template <class T, class Enum, uint8_t = error_category<Enum>::value>
enable_if_has_make_error_t<E, bool> operator!=(E x, const expected<T>& y) { bool operator!=(Enum x, const expected<T>& y) {
return !(x == y); return !(x == y);
} }
...@@ -390,8 +391,8 @@ public: ...@@ -390,8 +391,8 @@ public:
// nop // nop
} }
template <class Code, class E = enable_if_has_make_error_t<Code>> template <class Enum, uint8_t = error_category<Enum>::value>
expected(Code code) : error_(make_error(code)) { expected(Enum code) : error_(code) {
// nop // nop
} }
......
...@@ -19,15 +19,10 @@ ...@@ -19,15 +19,10 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include <map>
#include <memory> #include <memory>
#include <tuple>
#include <vector> #include <vector>
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/detail/is_one_of.hpp"
#include "caf/detail/is_primitive_config_value.hpp"
#include "caf/timespan.hpp"
namespace caf { namespace caf {
...@@ -177,8 +172,8 @@ config_option make_config_option(T& storage, string_view category, ...@@ -177,8 +172,8 @@ config_option make_config_option(T& storage, string_view category,
// -- enums -------------------------------------------------------------------- // -- enums --------------------------------------------------------------------
enum class atom_value : uint64_t;
enum class byte : uint8_t; enum class byte : uint8_t;
enum class pec : uint8_t;
enum class sec : uint8_t; enum class sec : uint8_t;
enum class stream_priority; enum class stream_priority;
enum class invoke_message_result; enum class invoke_message_result;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#pragma once #pragma once
#include <limits>
#include <utility> #include <utility>
#include "caf/config.hpp" #include "caf/config.hpp"
......
...@@ -81,12 +81,6 @@ public: ...@@ -81,12 +81,6 @@ public:
/// Returns the current time. /// Returns the current time.
clock_type::time_point now() const noexcept; clock_type::time_point now() const noexcept;
/// Returns the difference between `t0` and `t1`, allowing the clock to
/// return any arbitrary value depending on the measurement that took place.
clock_type::duration
difference(atom_value measurement, clock_type::time_point t0,
clock_type::time_point t1);
// -- timeout management ----------------------------------------------------- // -- timeout management -----------------------------------------------------
/// Requests a new timeout for `mid`. /// Requests a new timeout for `mid`.
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#include <unordered_map> #include <unordered_map>
#include "caf/abstract_actor.hpp" #include "caf/abstract_actor.hpp"
#include "caf/atom.hpp"
#include "caf/config.hpp" #include "caf/config.hpp"
#include "caf/deep_to_string.hpp" #include "caf/deep_to_string.hpp"
#include "caf/detail/arg_wrapper.hpp" #include "caf/detail/arg_wrapper.hpp"
...@@ -115,7 +114,7 @@ public: ...@@ -115,7 +114,7 @@ public:
event& operator=(const event&) = default; event& operator=(const event&) = default;
event(unsigned lvl, unsigned line, atom_value cat, string_view full_fun, event(unsigned lvl, unsigned line, string_view cat, string_view full_fun,
string_view fun, string_view fn, std::string msg, std::thread::id t, string_view fun, string_view fn, std::string msg, std::thread::id t,
actor_id a, timestamp ts); actor_id a, timestamp ts);
...@@ -128,7 +127,7 @@ public: ...@@ -128,7 +127,7 @@ public:
unsigned line_number; unsigned line_number;
/// Name of the category (component) logging the event. /// Name of the category (component) logging the event.
atom_value category_name; string_view category_name;
/// Name of the current function as reported by `__PRETTY_FUNCTION__`. /// Name of the current function as reported by `__PRETTY_FUNCTION__`.
string_view pretty_fun; string_view pretty_fun;
...@@ -230,7 +229,7 @@ public: ...@@ -230,7 +229,7 @@ public:
/// Returns whether the logger is configured to accept input for given /// Returns whether the logger is configured to accept input for given
/// component and log level. /// component and log level.
bool accepts(unsigned level, atom_value component_name); bool accepts(unsigned level, string_view component_name);
/// Returns the output format used for the log file. /// Returns the output format used for the log file.
const line_format& file_format() const { const line_format& file_format() const {
...@@ -262,9 +261,6 @@ public: ...@@ -262,9 +261,6 @@ public:
/// Renders the name of a fully qualified function. /// Renders the name of a fully qualified function.
static void render_fun_name(std::ostream& out, const event& x); static void render_fun_name(std::ostream& out, const event& x);
/// Renders the difference between `t0` and `tn` in milliseconds.
static void render_time_diff(std::ostream& out, timestamp t0, timestamp tn);
/// Renders the date of `x` in ISO 8601 format. /// Renders the date of `x` in ISO 8601 format.
static void render_date(std::ostream& out, timestamp x); static void render_date(std::ostream& out, timestamp x);
...@@ -347,7 +343,7 @@ private: ...@@ -347,7 +343,7 @@ private:
config cfg_; config cfg_;
// Filters events by component name. // Filters events by component name.
std::vector<atom_value> component_blacklist; std::vector<std::string> component_blacklist;
// References the parent system. // References the parent system.
actor_system& system_; actor_system& system_;
...@@ -414,8 +410,8 @@ CAF_CORE_EXPORT bool operator==(const logger::field& x, const logger::field& y); ...@@ -414,8 +410,8 @@ CAF_CORE_EXPORT bool operator==(const logger::field& x, const logger::field& y);
#define CAF_CAT(a, b) a##b #define CAF_CAT(a, b) a##b
#define CAF_LOG_MAKE_EVENT(aid, component, loglvl, message) \ #define CAF_LOG_MAKE_EVENT(aid, component, loglvl, message) \
::caf::logger::event(loglvl, __LINE__, caf::atom(component), CAF_PRETTY_FUN, \ ::caf::logger::event(loglvl, __LINE__, component, CAF_PRETTY_FUN, __func__, \
__func__, caf::logger::skip_path(__FILE__), \ caf::logger::skip_path(__FILE__), \
(::caf::logger::line_builder{} << message).get(), \ (::caf::logger::line_builder{} << message).get(), \
::std::this_thread::get_id(), aid, \ ::std::this_thread::get_id(), aid, \
::caf::make_timestamp()) ::caf::make_timestamp())
...@@ -436,7 +432,7 @@ CAF_CORE_EXPORT bool operator==(const logger::field& x, const logger::field& y); ...@@ -436,7 +432,7 @@ CAF_CORE_EXPORT bool operator==(const logger::field& x, const logger::field& y);
do { \ do { \
auto CAF_UNIFYN(caf_logger) = caf::logger::current_logger(); \ auto CAF_UNIFYN(caf_logger) = caf::logger::current_logger(); \
if (CAF_UNIFYN(caf_logger) != nullptr \ if (CAF_UNIFYN(caf_logger) != nullptr \
&& CAF_UNIFYN(caf_logger)->accepts(loglvl, caf::atom(component))) \ && CAF_UNIFYN(caf_logger)->accepts(loglvl, component)) \
CAF_UNIFYN(caf_logger) \ CAF_UNIFYN(caf_logger) \
->log(CAF_LOG_MAKE_EVENT(CAF_UNIFYN(caf_logger)->thread_local_aid(), \ ->log(CAF_LOG_MAKE_EVENT(CAF_UNIFYN(caf_logger)->thread_local_aid(), \
component, loglvl, message)); \ component, loglvl, message)); \
......
...@@ -35,7 +35,7 @@ R make_actor(actor_id aid, node_id nid, actor_system* sys, Ts&&... xs) { ...@@ -35,7 +35,7 @@ R make_actor(actor_id aid, node_id nid, actor_system* sys, Ts&&... xs) {
#if CAF_LOG_LEVEL >= CAF_LOG_LEVEL_DEBUG #if CAF_LOG_LEVEL >= CAF_LOG_LEVEL_DEBUG
actor_storage<T>* ptr = nullptr; actor_storage<T>* ptr = nullptr;
if (logger::current_logger()->accepts(CAF_LOG_LEVEL_DEBUG, if (logger::current_logger()->accepts(CAF_LOG_LEVEL_DEBUG,
caf::atom(CAF_LOG_FLOW_COMPONENT))) { CAF_LOG_FLOW_COMPONENT)) {
std::string args; std::string args;
args = deep_to_string(std::forward_as_tuple(xs...)); args = deep_to_string(std::forward_as_tuple(xs...));
ptr ptr
......
...@@ -47,11 +47,6 @@ struct unbox_message_element<T, 0> { ...@@ -47,11 +47,6 @@ struct unbox_message_element<T, 0> {
using type = T; using type = T;
}; };
template <atom_value V>
struct unbox_message_element<atom_constant<V>, 0> {
using type = atom_value;
};
template <> template <>
struct unbox_message_element<actor_control_block*, 0> { struct unbox_message_element<actor_control_block*, 0> {
using type = strong_actor_ptr; using type = strong_actor_ptr;
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include "caf/detail/int_list.hpp" #include "caf/detail/int_list.hpp"
#include "caf/detail/invoke_result_visitor.hpp" #include "caf/detail/invoke_result_visitor.hpp"
#include "caf/detail/pseudo_tuple.hpp" #include "caf/detail/pseudo_tuple.hpp"
#include "caf/detail/try_match.hpp"
#include "caf/detail/type_list.hpp" #include "caf/detail/type_list.hpp"
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
#include "caf/match_case.hpp" #include "caf/match_case.hpp"
...@@ -41,8 +40,7 @@ class CAF_CORE_EXPORT match_case { ...@@ -41,8 +40,7 @@ class CAF_CORE_EXPORT match_case {
public: public:
enum result { no_match, match, skip }; enum result { no_match, match, skip };
match_case(uint32_t tt); match_case() = default;
match_case(match_case&&) = default; match_case(match_case&&) = default;
match_case(const match_case&) = default; match_case(const match_case&) = default;
...@@ -52,13 +50,6 @@ public: ...@@ -52,13 +50,6 @@ public:
virtual result virtual result
invoke(detail::invoke_result_visitor& rv, type_erased_tuple& xs) invoke(detail::invoke_result_visitor& rv, type_erased_tuple& xs)
= 0; = 0;
inline uint32_t type_token() const {
return token_;
}
private:
uint32_t token_;
}; };
template <bool IsVoid, class F> template <bool IsVoid, class F>
...@@ -123,16 +114,13 @@ public: ...@@ -123,16 +114,13 @@ public:
trivial_match_case& operator=(trivial_match_case&&) = default; trivial_match_case& operator=(trivial_match_case&&) = default;
trivial_match_case& operator=(const trivial_match_case&) = default; trivial_match_case& operator=(const trivial_match_case&) = default;
trivial_match_case(F f) trivial_match_case(F f) : fun_(std::move(f)) {
: match_case(make_type_token_from_list<pattern>()), fun_(std::move(f)) {
// nop // nop
} }
match_case::result match_case::result
invoke(detail::invoke_result_visitor& f, type_erased_tuple& xs) override { invoke(detail::invoke_result_visitor& f, type_erased_tuple& xs) override {
detail::meta_elements<pattern> ms; if (!xs.match_elements(pattern{}))
// check if try_match() reports success
if (!detail::try_match(xs, ms.arr.data(), ms.arr.size()))
return match_case::no_match; return match_case::no_match;
typename detail::il_indices<decayed_arg_types>::type indices; typename detail::il_indices<decayed_arg_types>::type indices;
lfinvoker<std::is_same<result_type, void>::value, F> fun{fun_}; lfinvoker<std::is_same<result_type, void>::value, F> fun{fun_};
...@@ -150,14 +138,9 @@ protected: ...@@ -150,14 +138,9 @@ protected:
}; };
struct match_case_info { struct match_case_info {
uint32_t type_token;
match_case* ptr; match_case* ptr;
}; };
inline bool operator<(const match_case_info& x, const match_case_info& y) {
return x.type_token < y.type_token;
}
template <class F> template <class F>
typename std::enable_if<!std::is_base_of<match_case, F>::value, typename std::enable_if<!std::is_base_of<match_case, F>::value,
std::tuple<trivial_match_case<F>>>::type std::tuple<trivial_match_case<F>>>::type
......
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
#include "caf/atom.hpp"
#include "caf/config.hpp" #include "caf/config.hpp"
#include "caf/detail/apply_args.hpp" #include "caf/detail/apply_args.hpp"
#include "caf/detail/comparable.hpp" #include "caf/detail/comparable.hpp"
...@@ -77,8 +76,6 @@ public: ...@@ -77,8 +76,6 @@ public:
size_t size() const noexcept override; size_t size() const noexcept override;
uint32_t type_token() const noexcept override;
rtti_pair type(size_t pos) const noexcept override; rtti_pair type(size_t pos) const noexcept override;
const void* get(size_t pos) const noexcept override; const void* get(size_t pos) const noexcept override;
......
...@@ -139,7 +139,7 @@ protected: ...@@ -139,7 +139,7 @@ protected:
template <class F> template <class F>
bool handle_system_message(mailbox_element& x, execution_unit* context, bool handle_system_message(mailbox_element& x, execution_unit* context,
bool trap_exit, F& down_msg_handler) { bool trap_exit, F& down_msg_handler) {
if (x.content().type_token() == make_type_token<down_msg>()) { if (x.content().match_elements<down_msg>()) {
down_msg_handler(x.content().get_mutable_as<down_msg>(0)); down_msg_handler(x.content().get_mutable_as<down_msg>(0));
return true; return true;
} }
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include <cstddef> #include <cstddef>
#include "caf/atom.hpp"
#include "caf/deep_to_string.hpp" #include "caf/deep_to_string.hpp"
#include "caf/meta/type_name.hpp" #include "caf/meta/type_name.hpp"
...@@ -28,7 +27,7 @@ namespace caf { ...@@ -28,7 +27,7 @@ namespace caf {
/// Stores a flow-control configuration. /// Stores a flow-control configuration.
struct named_actor_config { struct named_actor_config {
atom_value strategy; std::string strategy;
size_t low_watermark; size_t low_watermark;
size_t max_pending; size_t max_pending;
}; };
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include <functional> #include <functional>
#include <string> #include <string>
#include "caf/atom.hpp"
#include "caf/detail/comparable.hpp" #include "caf/detail/comparable.hpp"
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
...@@ -48,7 +47,7 @@ public: ...@@ -48,7 +47,7 @@ public:
virtual size_t hash_code() const noexcept = 0; virtual size_t hash_code() const noexcept = 0;
virtual atom_value implementation_id() const noexcept = 0; virtual uint8_t implementation_id() const noexcept = 0;
virtual int compare(const data& other) const noexcept = 0; virtual int compare(const data& other) const noexcept = 0;
...@@ -72,7 +71,7 @@ public: ...@@ -72,7 +71,7 @@ public:
static constexpr size_t host_id_size = 20; static constexpr size_t host_id_size = 20;
/// Identifies this data implementation type. /// Identifies this data implementation type.
static constexpr atom_value class_id = atom("default"); static constexpr uint8_t class_id = 1;
// -- member types --------------------------------------------------------- // -- member types ---------------------------------------------------------
...@@ -110,7 +109,7 @@ public: ...@@ -110,7 +109,7 @@ public:
size_t hash_code() const noexcept override; size_t hash_code() const noexcept override;
atom_value implementation_id() const noexcept override; uint8_t implementation_id() const noexcept override;
int compare(const data& other) const noexcept override; int compare(const data& other) const noexcept override;
...@@ -138,7 +137,7 @@ public: ...@@ -138,7 +137,7 @@ public:
// -- constants ------------------------------------------------------------ // -- constants ------------------------------------------------------------
/// Identifies this data implementation type. /// Identifies this data implementation type.
static constexpr atom_value class_id = atom("uri"); static constexpr uint8_t class_id = 2;
// -- constructors, destructors, and assignment operators ------------------ // -- constructors, destructors, and assignment operators ------------------
...@@ -158,7 +157,7 @@ public: ...@@ -158,7 +157,7 @@ public:
size_t hash_code() const noexcept override; size_t hash_code() const noexcept override;
atom_value implementation_id() const noexcept override; uint8_t implementation_id() const noexcept override;
int compare(const data& other) const noexcept override; int compare(const data& other) const noexcept override;
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include <type_traits> #include <type_traits>
#include "caf/atom.hpp" #include "caf/fwd.hpp"
namespace caf { namespace caf {
...@@ -87,15 +87,12 @@ private: ...@@ -87,15 +87,12 @@ private:
/// Converts `T` to `param<T>` unless `T` is arithmetic, an atom constant, or /// Converts `T` to `param<T>` unless `T` is arithmetic, an atom constant, or
/// a stream handshake. /// a stream handshake.
template <class T> template <class T>
struct add_param : std::conditional<std::is_arithmetic<T>::value, T, param<T>> { struct add_param
: std::conditional<std::is_arithmetic<T>::value || std::is_empty<T>::value, T,
param<T>> {
// nop // nop
}; };
template <atom_value V>
struct add_param<atom_constant<V>> {
using type = atom_constant<V>;
};
template <class T> template <class T>
struct add_param<stream<T>> { struct add_param<stream<T>> {
using type = stream<T>; using type = stream<T>;
......
...@@ -18,11 +18,11 @@ ...@@ -18,11 +18,11 @@
#pragma once #pragma once
#include <cstddef>
#include <cstdint> #include <cstdint>
#include <string> #include <string>
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/error_category.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
namespace caf { namespace caf {
...@@ -80,15 +80,9 @@ enum class pec : uint8_t { ...@@ -80,15 +80,9 @@ enum class pec : uint8_t {
/// @relates pec /// @relates pec
CAF_CORE_EXPORT std::string to_string(pec); CAF_CORE_EXPORT std::string to_string(pec);
/// Returns an error object from given error code. template <>
CAF_CORE_EXPORT error make_error(pec code); struct error_category<pec> {
static constexpr uint8_t value = 1;
/// Returns an error object from given error code with additional context };
/// information for where the parser stopped in the input.
CAF_CORE_EXPORT error make_error(pec code, int32_t line, int32_t column);
/// Returns an error object from given error code with additional context
/// information for where the parser stopped in the argument.
CAF_CORE_EXPORT error make_error(pec code, string_view argument);
} // namespace caf } // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <new>
#include <cstdint>
#include <typeinfo>
#include <stdexcept>
#include <type_traits>
#include "caf/atom.hpp"
#include "caf/none.hpp"
#include "caf/variant.hpp"
namespace caf {
using primitive_variant = variant<int8_t, int16_t, int32_t, int64_t,
uint8_t, uint16_t, uint32_t, uint64_t,
float, double, long double,
std::string, std::u16string, std::u32string,
atom_value, bool>;
} // namespace caf
...@@ -48,8 +48,8 @@ public: ...@@ -48,8 +48,8 @@ public:
value = make_message(Ts{std::forward<Us>(xs)}...); value = make_message(Ts{std::forward<Us>(xs)}...);
} }
template <class E, class = enable_if_has_make_error_t<E>> template <class Enum, uint8_t = error_category<Enum>::value>
result(E x) : flag(rt_error), err(make_error(x)) { result(Enum x) : flag(rt_error), err(make_error(x)) {
// nop // nop
} }
...@@ -109,8 +109,8 @@ public: ...@@ -109,8 +109,8 @@ public:
// nop // nop
} }
template <class E, class = enable_if_has_make_error_t<E>> template <class Enum, uint8_t = error_category<Enum>::value>
result(E x) : flag(rt_error), err(make_error(x)) { result(Enum x) : flag(rt_error), err(make_error(x)) {
// nop // nop
} }
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <cstdint>
#include <unordered_map>
#include "caf/atom.hpp"
#include "caf/detail/core_export.hpp"
#include "caf/detail/shared_spinlock.hpp"
#include "caf/variant.hpp"
namespace caf {
/// Thread-safe container for mapping atoms to arbitrary settings.
class CAF_CORE_EXPORT runtime_settings_map {
public:
// -- member types -----------------------------------------------------------
using mutex_type = detail::shared_spinlock;
using generic_pointer = void*;
using generic_function_pointer = void (*)();
using mapped_type = variant<none_t, int64_t, uint64_t, atom_value,
generic_pointer, generic_function_pointer>;
// -- thread-safe access -----------------------------------------------------
/// Returns the value mapped to `key`.
mapped_type get(atom_value key) const;
/// Returns the value mapped to `key` or `fallback` if no value is mapped to
/// this key.
mapped_type get_or(atom_value key, mapped_type fallback) const;
/// Maps `key` to `value` and returns the previous value.
void set(atom_value key, mapped_type value);
/// Removes `key` from the map.
void erase(atom_value key);
/// Returns the number of key-value entries.
size_t size() const;
/// Returns whether `size()` equals 0.
bool empty() const {
return size() == 0;
}
private:
// -- member variables -------------------------------------------------------
mutable mutex_type mtx_;
std::unordered_map<atom_value, mapped_type> map_;
};
} // namespace caf
...@@ -803,7 +803,7 @@ public: ...@@ -803,7 +803,7 @@ public:
// -- timeout management ----------------------------------------------------- // -- timeout management -----------------------------------------------------
/// Requests a new timeout and returns its ID. /// Requests a new timeout and returns its ID.
uint64_t set_timeout(atom_value type, actor_clock::time_point x); uint64_t set_timeout(std::string type, actor_clock::time_point x);
// -- stream processing ------------------------------------------------------ // -- stream processing ------------------------------------------------------
......
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
#include "caf/actor_cast.hpp" #include "caf/actor_cast.hpp"
#include "caf/actor_clock.hpp" #include "caf/actor_clock.hpp"
#include "caf/actor_system.hpp" #include "caf/actor_system.hpp"
#include "caf/atom.hpp"
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/message.hpp" #include "caf/message.hpp"
......
...@@ -22,9 +22,11 @@ ...@@ -22,9 +22,11 @@
#pragma once #pragma once
#include <cstdint>
#include <string> #include <string>
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/error_category.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
namespace caf { namespace caf {
...@@ -148,17 +150,9 @@ enum class sec : uint8_t { ...@@ -148,17 +150,9 @@ enum class sec : uint8_t {
/// @relates sec /// @relates sec
CAF_CORE_EXPORT std::string to_string(sec); CAF_CORE_EXPORT std::string to_string(sec);
/// @relates sec template <>
CAF_CORE_EXPORT error make_error(sec); struct error_category<sec> {
static constexpr uint8_t value = 0;
/// @relates sec };
CAF_CORE_EXPORT error make_error(sec, message);
/// @relates sec
template <class T, class... Ts>
auto make_error(sec code, T&& x, Ts&&... xs) {
return make_error(code,
make_message(std::forward<T>(x), std::forward<Ts>(xs)...));
}
} // namespace caf } // namespace caf
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include "caf/byte.hpp" #include "caf/byte.hpp"
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/error.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/meta/annotation.hpp" #include "caf/meta/annotation.hpp"
#include "caf/meta/save_callback.hpp" #include "caf/meta/save_callback.hpp"
...@@ -124,7 +123,7 @@ public: ...@@ -124,7 +123,7 @@ public:
virtual result_type apply(const std::u32string& x) = 0; virtual result_type apply(const std::u32string& x) = 0;
template <class Enum, class = std::enable_if_t<std::is_enum<Enum>::value>> template <class Enum, class = std::enable_if_t<std::is_enum<Enum>::value>>
result_type apply(Enum x) { auto apply(Enum x) {
return apply(static_cast<std::underlying_type_t<Enum>>(x)); return apply(static_cast<std::underlying_type_t<Enum>>(x));
} }
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "caf/config_value.hpp" #include "caf/config_value.hpp"
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/detail/move_if_not_ptr.hpp"
#include "caf/dictionary.hpp" #include "caf/dictionary.hpp"
#include "caf/optional.hpp" #include "caf/optional.hpp"
#include "caf/raise_error.hpp" #include "caf/raise_error.hpp"
...@@ -39,11 +40,10 @@ get_if(const settings* xs, string_view name); ...@@ -39,11 +40,10 @@ get_if(const settings* xs, string_view name);
/// Tries to retrieve the value associated to `name` from `xs`. /// Tries to retrieve the value associated to `name` from `xs`.
/// @relates config_value /// @relates config_value
template <class T> template <class T>
optional<T> get_if(const settings* xs, string_view name) { auto get_if(const settings* xs, string_view name) {
if (auto value = get_if(xs, name)) auto value = get_if(xs, name);
if (auto ptr = get_if<T>(value)) using result_type = decltype(get_if<T>(value));
return *ptr; return value ? get_if<T>(value) : result_type{};
return none;
} }
/// Returns whether `xs` associates a value of type `T` to `name`. /// Returns whether `xs` associates a value of type `T` to `name`.
...@@ -59,8 +59,8 @@ bool holds_alternative(const settings& xs, string_view name) { ...@@ -59,8 +59,8 @@ bool holds_alternative(const settings& xs, string_view name) {
template <class T> template <class T>
T get(const settings& xs, string_view name) { T get(const settings& xs, string_view name) {
auto result = get_if<T>(&xs, name); auto result = get_if<T>(&xs, name);
CAF_ASSERT(result != none); CAF_ASSERT(result);
return std::move(*result); return detail::move_if_not_ptr(result);
} }
template <class T, class = typename std::enable_if< template <class T, class = typename std::enable_if<
......
This diff is collapsed.
...@@ -88,8 +88,8 @@ typename Inspector::result_type inspect(Inspector& f, group_down_msg& x) { ...@@ -88,8 +88,8 @@ typename Inspector::result_type inspect(Inspector& f, group_down_msg& x) {
/// Signalizes a timeout event. /// Signalizes a timeout event.
/// @note This message is handled implicitly by the runtime system. /// @note This message is handled implicitly by the runtime system.
struct timeout_msg { struct timeout_msg {
/// Type of the timeout (either `receive_atom` or `cycle_atom`). /// Type of the timeout (usually either "receive" or "cycle").
atom_value type; std::string type;
/// Actor-specific timeout ID. /// Actor-specific timeout ID.
uint64_t timeout_id; uint64_t timeout_id;
}; };
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment