Commit 5f8abef0 authored by Dominik Charousset's avatar Dominik Charousset

Add documentation of `message` to manual

parent 22f260bb
\section{Common Pitfalls} \section{Common Pitfalls}
\label{Sec::Pitfalls} \label{Sec::Pitfalls}
\subsection{Defining Patterns}
\begin{itemize}
\item C++ evaluates comma-separated expressions from left-to-right, using only the last element as return type of the whole expression. This means that message handlers and behaviors must \emph{not} be initialized like this:
\begin{lstlisting}
message_handler wrong = (
[](int i) { /*...*/ },
[](float f) { /*...*/ }
);
\end{lstlisting}
The correct way to initialize message handlers and behaviors is to either use the constructor or the member function \lstinline^assign^:
\begin{lstlisting}
message_handler ok1{
[](int i) { /*...*/ },
[](float f) { /*...*/ }
};
message_handler ok2;
// some place later
ok2.assign(
[](int i) { /*...*/ },
[](float f) { /*...*/ }
);
\end{lstlisting}
\end{itemize}
\subsection{Event-Based API} \subsection{Event-Based API}
\begin{itemize} \begin{itemize}
...@@ -15,7 +41,6 @@ Thus, one should \textit{always} capture by value in lambda expressions, because ...@@ -15,7 +41,6 @@ Thus, one should \textit{always} capture by value in lambda expressions, because
\item \item
A handle returned by \lstinline^sync_send^ represents \emph{exactly one} response message. A handle returned by \lstinline^sync_send^ represents \emph{exactly one} response message.
Therefore, it is not possible to receive more than one response message. Therefore, it is not possible to receive more than one response message.
%Calling \lstinline^reply^ more than once will result in lost messages and calling \lstinline^handle_response^ or \lstinline^receive_response^ more than once on a future will throw an exception.
\item \item
The handle returned by \lstinline^sync_send^ is bound to the calling actor. The handle returned by \lstinline^sync_send^ is bound to the calling actor.
...@@ -23,6 +48,7 @@ It is not possible to transfer a handle to a response to another actor. ...@@ -23,6 +48,7 @@ It is not possible to transfer a handle to a response to another actor.
\end{itemize} \end{itemize}
\clearpage
\subsection{Sharing} \subsection{Sharing}
\begin{itemize} \begin{itemize}
......
\section{Messages}
Messages in \lib are type-erased, copy-on-write tuples.
The actual message type itself is usually hidden, as actors use pattern matching to decompose messages automatically.
However, the classes \lstinline^message^ and \lstinline^message_builder^ allow more advanced usage scenarios than only sending data from one actor to another.
\subsection{Class \texttt{message}}
{\small
\begin{tabular*}{\textwidth}{m{0.45\textwidth}m{0.5\textwidth}}
\multicolumn{2}{m{\linewidth}}{\large{\textbf{Member functions}}\vspace{3pt}} \\
\\
\multicolumn{2}{l}{\textbf{Observers}\vspace{3pt}} \\
\hline
\lstinline^bool empty()^ & Returns whether this message is empty \\
\hline
\lstinline^size_t size()^ & Returns the size of this message \\
\hline
\lstinline^const void* at(size_t p)^ & Returns a const pointer to the element at position \lstinline^p^ \\
\hline
\lstinline^template <class T>^ \lstinline^const T& get_as(size_t p)^ & Returns a const ref. to the element at position \lstinline^p^ \\
\hline
\lstinline^template <class T>^ \lstinline^bool match_element(size_t p)^ & Returns whether the element at position \lstinline^p^ has type \lstinline^T^ \\
\hline
\lstinline^template <class... Ts>^ \lstinline^bool match_elements()^ & Returns whether this message has the types \lstinline^Ts...^ \\
\hline
\lstinline^message drop(size_t n)^ & Creates a new message with all but the first \lstinline^n^ values \\
\hline
\lstinline^message drop_right(size_t n)^ & Creates a new message with all but the last \lstinline^n^ values \\
\hline
\lstinline^message take(size_t n)^ & Creates a new message from the first \lstinline^n^ values \\
\hline
\lstinline^message take_right(size_t n)^ & Creates a new message from the last \lstinline^n^ values \\
\hline
\lstinline^message slice(size_t p, size_t n)^ & Creates a new message from \lstinline^[p, p + n)^ \\
\hline
\lstinline^message slice(size_t p, size_t n)^ & Creates a new message from \lstinline^[p, p + n)^ \\
\hline
\lstinline^message filter(message_handler)^ & See \ref{Sec::Messages::Filter} \\
\hline
\lstinline^message filter_cli(...)^ & See \ref{Sec::Messages::FilterCLI} \\
\hline
\\
\multicolumn{2}{l}{\textbf{Modifiers}\vspace{3pt}} \\
\hline
\lstinline^optional<message>^ \lstinline^apply(message_handler f)^ & Returns \lstinline^f(*this)^ \\
\hline
\lstinline^void* mutable_at(size_t p)^ & Returns a pointer to the element at position p \\
\hline
\lstinline^template <class T>^ \lstinline^T& get_as_mutable(size_t p)^ & Returns a reference to the element at position p \\
\hline
\end{tabular*}
}
\clearpage
\subsection{Class \texttt{message\_builder}}
{\small
\begin{tabular*}{\textwidth}{m{0.45\textwidth}m{0.5\textwidth}}
\multicolumn{2}{m{\linewidth}}{\large{\textbf{Member functions}}\vspace{3pt}} \\
\\
\multicolumn{2}{l}{\textbf{Constructors}\vspace{3pt}} \\
\hline
\lstinline^()^ & Creates an empty message builder \\
\hline
\lstinline^template <class Iter>^ \lstinline^(Iter first, Iter last)^ & Adds all elements from range \lstinline^[first, last)^ \\
\hline
\\
\multicolumn{2}{l}{\textbf{Observers}\vspace{3pt}} \\
\hline
\lstinline^bool empty()^ & Returns whether this message is empty \\
\hline
\lstinline^size_t size()^ & Returns the size of this message \\
\hline
\lstinline^message to_message( )^ & Converts the buffer to an actual message object \\
\hline
\lstinline^template <class T>^ \lstinline^append(T val)^ & Adds \lstinline^val^ to the buffer \\
\hline
\lstinline^template <class Iter>^ \lstinline^append(Iter first, Iter last)^ & Adds all elements from range \lstinline^[first, last)^ \\
\hline
\lstinline^message filter(message_handler)^ & See \ref{Sec::Messages::Filter} \\
\hline
\lstinline^message filter_cli(...)^ & See \ref{Sec::Messages::FilterCLI} \\
\hline
\\
\multicolumn{2}{l}{\textbf{Modifiers}\vspace{3pt}} \\
\hline
\lstinline^optional<message>^ \lstinline^apply(message_handler f)^ & Returns \lstinline^f(*this)^ \\
\hline
\lstinline^message move_to_message()^ & Transfers ownership of its data to the new message \textbf{Warning}: this function leaves the builder in an \emph{invalid state}, i.e., calling any member function on it afterwards is undefined behavior \\
\hline
\end{tabular*}
}
\clearpage
\subsection{Filtering}
\label{Sec::Messages::Filter}
Messages are filtered by repeatedly applying a message handler to the greatest remaining slice, whereas slices are generated in the sequence \lstinline^[0, size)^, \lstinline^[0, size-1)^, \lstinline^...^, \lstinline^[1, size-1)^, \lstinline^...^, \lstinline^[size-1, size)^.
Whenever a slice matches, it is removed from the message and the next slice starts at the same index on the reduced message.
For example:
\begin{lstlisting}
auto msg = make_message(1, 2.f, 3.f, 4);
// filter float and integer pairs
auto msg2 = msg.filter({
[](float, float) { },
[](int, int) { }
});
assert(msg2 == make_message(1, 4));
\end{lstlisting}
Step-by-step explanation:
\begin{itemize}
\item Slice 1: \lstinline^(1, 2.f, 3.f, 4)^, no match
\item Slice 2: \lstinline^(1, 2.f, 3.f)^, no match
\item Slice 3: \lstinline^(1, 2.f)^, no match
\item Slice 4: \lstinline^(1)^, no match
\item Slice 5: \lstinline^(2.f, 3.f, 4)^, no match
\item Slice 6: \lstinline^(2.f, 3.f)^, \emph{match}; new message is \lstinline^(1, 4)^
\item Slice 7: \lstinline^(4)^, no match
\end{itemize}
Slice 7 is \lstinline^(4)^, i.e., does not contain the first element, because the match on slice 6 occurred at index position 1. The function filter iterates a message only once, from left to right. The result of \lstinline^message::filter^ is the remainder, i.e., a message consisting of all unmatched elements.
\clearpage
\subsection{Filter and Command Line Arguments}
\label{Sec::Messages::FilterCLI}
The class \lstinline^message^ also contains a convenience interface to \lstinline^filter^ for parsing command line arguments: \lstinline^filter_cli^.
This member function provides a simplistic interface for defining a command line argument parsers:
\begin{lstlisting}
int main(int argc, char** argv) {
uint16_t port;
string host = "localhost";
auto res = message_builder(argv + 1, argv + argc).filter_cli({
{"port,p", "set port", port},
{"host,H", "set host (default: localhost)", host},
{"verbose,v", "enable verbose mode"}
});
if (res.opts.count("help") > 0) {
// CLI arguments contained "-h", "--help", or "-?" (builtin);
// note: the help text has already been printed to stdout
return 0;
}
if (!res.remainder.empty()) {
// ... filter did not consume all CLI arguments ...
}
if (res.opts.count("verbose") > 0) {
// ... enable verbose mode ...
}
// ...
}
\end{lstlisting}
...@@ -129,6 +129,7 @@ ...@@ -129,6 +129,7 @@
\include{TypeSystem} \include{TypeSystem}
\include{BlockingAPI} \include{BlockingAPI}
\include{StronglyTypedActors} \include{StronglyTypedActors}
\include{Messages}
\include{CommonPitfalls} \include{CommonPitfalls}
\include{Appendix} \include{Appendix}
......
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