Commit 1a35bf3b authored by Dominik Charousset's avatar Dominik Charousset

Merge branch 'issue/956'

parents 1b1aae99 18e800a8
...@@ -32,6 +32,8 @@ IndentWidth: 2 ...@@ -32,6 +32,8 @@ IndentWidth: 2
IndentWrappedFunctionNames: false IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false KeepEmptyLinesAtTheStartOfBlocks: false
Language: Cpp Language: Cpp
MacroBlockBegin: "^BEGIN_STATE$"
MacroBlockEnd: "^END_STATE$"
MaxEmptyLinesToKeep: 1 MaxEmptyLinesToKeep: 1
NamespaceIndentation: None NamespaceIndentation: None
PenaltyBreakAssignment: 1000 PenaltyBreakAssignment: 1000
......
...@@ -654,11 +654,6 @@ message(STATUS "Set release version for all documentation to ${CAF_RELEASE}.") ...@@ -654,11 +654,6 @@ message(STATUS "Set release version for all documentation to ${CAF_RELEASE}.")
# -- Setup for building manual and API documentation --------------------------- # -- Setup for building manual and API documentation ---------------------------
# we need the examples and some headers relative to the build/doc/tex directory
file(COPY examples/ DESTINATION examples)
file(COPY libcaf_core/caf/exit_reason.hpp DESTINATION libcaf_core/caf/)
file(COPY libcaf_core/caf/sec.hpp DESTINATION libcaf_core/caf/)
add_subdirectory(doc) add_subdirectory(doc)
################################################################################ ################################################################################
......
cmake_minimum_required(VERSION 2.8.12)
project(doc NONE)
add_custom_target(doc) add_custom_target(doc)
# -- list all .tex source files ------------------------------------------------ # -- list all .tex source files ------------------------------------------------
...@@ -34,20 +30,22 @@ set(sources ...@@ -34,20 +30,22 @@ set(sources
tex/Testing.tex tex/Testing.tex
) )
# -- process .in files ----------------------------------------------------- # -- create target folders -----------------------------------------------------
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/tex")
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/rst")
# -- process .in files ---------------------------------------------------------
configure_file("cmake/Doxyfile.in" configure_file("cmake/Doxyfile.in"
"${CMAKE_CURRENT_BINARY_DIR}/Doxyfile" "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile"
@ONLY) @ONLY)
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/tex")
configure_file("cmake/variables.tex.in" configure_file("cmake/variables.tex.in"
"${CMAKE_CURRENT_BINARY_DIR}/tex/variables.tex" "${CMAKE_CURRENT_BINARY_DIR}/tex/variables.tex"
@ONLY) @ONLY)
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/rst")
configure_file("cmake/conf.py.in" configure_file("cmake/conf.py.in"
"${CMAKE_CURRENT_BINARY_DIR}/rst/conf.py" "${CMAKE_CURRENT_BINARY_DIR}/rst/conf.py"
@ONLY) @ONLY)
...@@ -60,6 +58,50 @@ configure_file("cmake/index_header.rst.in" ...@@ -60,6 +58,50 @@ configure_file("cmake/index_header.rst.in"
"${CMAKE_CURRENT_BINARY_DIR}/rst/index_header.rst" "${CMAKE_CURRENT_BINARY_DIR}/rst/index_header.rst"
@ONLY) @ONLY)
# -- generate .rst files -------------------------------------------------------
add_executable(caf-generate-rst cmake/caf-generate-rst.cpp)
target_link_libraries(caf-generate-rst
${CAF_EXTRA_LDFLAGS}
${CAF_LIBRARIES}
${PTHREAD_LIBRARIES})
add_custom_target(rst)
add_dependencies(doc rst)
function(convert_to_rst tex_file)
get_filename_component(file_name "${tex_file}" NAME_WE)
set(input "${CMAKE_CURRENT_SOURCE_DIR}/tex/${tex_file}")
set(rst_file "${file_name}.rst")
set(output "${CMAKE_CURRENT_BINARY_DIR}/rst/${rst_file}")
add_custom_command(OUTPUT "${output}"
COMMAND
caf-generate-rst
-o "${output}"
-i "${input}"
-r "${PROJECT_SOURCE_DIR}"
DEPENDS caf-generate-rst "${input}")
add_custom_target("${rst_file}" DEPENDS "${output}")
add_dependencies(rst "${rst_file}")
endfunction()
foreach(filename ${sources})
get_filename_component(filename_no_dir "${filename}" NAME)
convert_to_rst("${filename_no_dir}")
endforeach()
# generate index.rst file from manual.tex
add_custom_target("index.rst"
DEPENDS "tex/manual.tex"
COMMAND "python"
"${CMAKE_SOURCE_DIR}/scripts/make_index_rst.py"
"${CMAKE_CURRENT_BINARY_DIR}/rst/index.rst"
"${CMAKE_SOURCE_DIR}/doc/tex/manual.tex"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/rst")
add_dependencies(rst "index.rst")
# -- Doxygen setup ------------------------------------------------------------- # -- Doxygen setup -------------------------------------------------------------
find_package(Doxygen) find_package(Doxygen)
...@@ -76,23 +118,6 @@ else() ...@@ -76,23 +118,6 @@ else()
add_dependencies(doc doxygen) add_dependencies(doc doxygen)
endif() endif()
# -- Pandoc utility macro ------------------------------------------------------
macro(generate_rst texfile)
get_filename_component(rstfile_we "${texfile}" NAME_WE)
set(rstfile "${rstfile_we}.rst")
set(bin_texfile "${CMAKE_CURRENT_BINARY_DIR}/${texfile}")
add_custom_target("${rstfile}"
DEPENDS "${bin_texfile}"
COMMAND ${PANDOC_EXECUTABLE}
"--filter=${CMAKE_SOURCE_DIR}/scripts/pandoc-filter.py"
--wrap=none -f latex
-o "${CMAKE_CURRENT_BINARY_DIR}/rst/${rstfile}"
"${bin_texfile}"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/rst")
add_dependencies(rst "${rstfile}")
endmacro()
# -- LaTeX setup --------------------------------------------------------------- # -- LaTeX setup ---------------------------------------------------------------
if (CAF_BUILD_TEX_MANUAL) if (CAF_BUILD_TEX_MANUAL)
...@@ -108,35 +133,5 @@ if (CAF_BUILD_TEX_MANUAL) ...@@ -108,35 +133,5 @@ if (CAF_BUILD_TEX_MANUAL)
FORCE_PDF FORCE_PDF
TARGET_NAME manual) TARGET_NAME manual)
add_dependencies(doc manual) add_dependencies(doc manual)
find_program(PANDOC_EXECUTABLE pandoc)
if(NOT EXISTS ${PANDOC_EXECUTABLE})
message(STATUS "Pandoc not found, skip generating reFormattedText version of the manual.")
else()
execute_process(COMMAND "python" "-c"
"from pandocfilters import toJSONFilter; print('ok')"
RESULT_VARIABLE has_pandocfilters
OUTPUT_QUIET
ERROR_QUIET)
if(NOT ${has_pandocfilters} EQUAL 0)
message(STATUS "Python with pandocfilters not found, skip generating reFormattedText version of the manual.")
else()
message(STATUS "Add optional target: rst.")
add_custom_target(rst)
add_dependencies(doc rst)
# generate .rst files for individual sections
foreach(texfile ${sources})
generate_rst(${texfile})
endforeach()
# generate index.rst file from manual.tex
add_custom_target("index.rst"
DEPENDS "tex/manual.tex"
COMMAND "python"
"${CMAKE_SOURCE_DIR}/scripts/make_index_rst.py"
"${CMAKE_CURRENT_BINARY_DIR}/rst/index.rst"
"${CMAKE_SOURCE_DIR}/doc/tex/manual.tex"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/rst")
add_dependencies(rst "index.rst")
endif()
endif()
endif() endif()
This diff is collapsed.
\newcommand{\cafrelease}{@CAF_RELEASE@} \newcommand{\cafrelease}{@CAF_RELEASE@}
\newcommand{\cafsha}{@CAF_SHA@} \newcommand{\cafsha}{@CAF_SHA@}
\newcommand{\cafroot}{@PROJECT_SOURCE_DIR@}
...@@ -40,7 +40,7 @@ TCP and returns a broker managing this connection on success. Finally, ...@@ -40,7 +40,7 @@ TCP and returns a broker managing this connection on success. Finally,
on success. There are no convenience functions spawn a UDP-based client or on success. There are no convenience functions spawn a UDP-based client or
server. server.
\subsection{Class \texttt{broker}} \subsection{Class \lstinline^broker^}
\label{broker-class} \label{broker-class}
\begin{lstlisting} \begin{lstlisting}
......
...@@ -6,66 +6,59 @@ programming in CAF. ...@@ -6,66 +6,59 @@ programming in CAF.
\subsection{Defining Message Handlers} \subsection{Defining Message Handlers}
\begin{itemize} C++ evaluates comma-separated expressions from left-to-right, using only the
\item C++ evaluates comma-separated expressions from left-to-right, using only last element as return type of the whole expression. This means that message
the last element as return type of the whole expression. This means that handlers and behaviors must \emph{not} be initialized like this:
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; \begin{lstlisting}
// some place later message_handler wrong = (
ok2.assign( [](int i) { /*...*/ },
[](int i) { /*...*/ }, [](float f) { /*...*/ }
[](float f) { /*...*/ } );
); \end{lstlisting}
\end{lstlisting}
\end{itemize} 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}
\subsection{Event-Based API} \subsection{Event-Based API}
\begin{itemize} The member function \lstinline^become^ does not block, i.e., always returns
\item The member function \lstinline^become^ does not block, i.e., always immediately. Thus, lambda expressions should \textit{always} capture by value.
returns immediately. Thus, lambda expressions should \textit{always} capture Otherwise, all references on the stack will cause undefined behavior if the
by value. Otherwise, all references on the stack will cause undefined lambda expression is executed.
behavior if the lambda expression is executed.
\end{itemize}
\subsection{Requests} \subsection{Requests}
\begin{itemize} A handle returned by \lstinline^request^ represents \emph{exactly one} response
\item A handle returned by \lstinline^request^ represents \emph{exactly one} message. It is not possible to receive more than one response message.
response message. It is not possible to receive more than one response
message.
\item The handle returned by \lstinline^request^ is bound to the calling actor.
It is not possible to transfer a handle to a response to another actor.
\end{itemize}
\clearpage The handle returned by \lstinline^request^ is bound to the calling actor. It is
not possible to transfer a handle to a response to another actor.
\clearpage
\subsection{Sharing} \subsection{Sharing}
\begin{itemize} It is strongly recommended to \textbf{not} share states between actors. In
\item It is strongly recommended to \textbf{not} share states between actors. particular, no actor shall ever access member variables or member functions of
In particular, no actor shall ever access member variables or member another actor. Accessing shared memory segments concurrently can cause undefined
functions of another actor. Accessing shared memory segments concurrently behavior that is incredibly hard to find and debug. However, sharing
can cause undefined behavior that is incredibly hard to find and debug. \textit{data} between actors is fine, as long as the data is \textit{immutable}
However, sharing \textit{data} between actors is fine, as long as the data and its lifetime is guaranteed to outlive all actors. The simplest way to meet
is \textit{immutable} and its lifetime is guaranteed to outlive all actors. the lifetime guarantee is by storing the data in smart pointers such as
The simplest way to meet the lifetime guarantee is by storing the data in \lstinline^std::shared_ptr^. Nevertheless, the recommended way of sharing
smart pointers such as \lstinline^std::shared_ptr^. Nevertheless, the informations is message passing. Sending the same message to multiple actors
recommended way of sharing informations is message passing. Sending the does not result in copying the data several times.
same message to multiple actors does not result in copying the data several
times.
\end{itemize}
...@@ -98,7 +98,7 @@ knowing the proper handle type. Pointers must be converted to a handle via ...@@ -98,7 +98,7 @@ knowing the proper handle type. Pointers must be converted to a handle via
\subsubsection{Spawning} \subsubsection{Spawning}
``Spawning'' an actor means to create and run a new actor. \emph{Spawning} an actor means to create and run a new actor.
\subsubsection{Monitor} \subsubsection{Monitor}
\label{monitor} \label{monitor}
......
...@@ -153,13 +153,15 @@ When passing the \lstinline^cells^ vector to our three different ...@@ -153,13 +153,15 @@ When passing the \lstinline^cells^ vector to our three different
implementations, we observe three outputs. Our \lstinline^waiting_testee^ actor implementations, we observe three outputs. Our \lstinline^waiting_testee^ actor
will always print: will always print:
{\footnotesize\begin{verbatim} \begin{footnotesize}
\begin{verbatim}
cell #9 -> 16 cell #9 -> 16
cell #8 -> 9 cell #8 -> 9
cell #7 -> 4 cell #7 -> 4
cell #6 -> 1 cell #6 -> 1
cell #5 -> 0 cell #5 -> 0
\end{verbatim}} \end{verbatim}
\end{footnotesize}
This is because \lstinline^await^ puts the one-shots handlers onto a stack and This is because \lstinline^await^ puts the one-shots handlers onto a stack and
enforces LIFO order by re-ordering incoming response messages. enforces LIFO order by re-ordering incoming response messages.
...@@ -170,13 +172,15 @@ immediately. ...@@ -170,13 +172,15 @@ immediately.
Finally, the \lstinline^blocking_testee^ implementation will always print: Finally, the \lstinline^blocking_testee^ implementation will always print:
{\footnotesize\begin{verbatim} \begin{footnotesize}
\begin{verbatim}
cell #5 -> 0 cell #5 -> 0
cell #6 -> 1 cell #6 -> 1
cell #7 -> 4 cell #7 -> 4
cell #8 -> 9 cell #8 -> 9
cell #9 -> 16 cell #9 -> 16
\end{verbatim}} \end{verbatim}
\end{footnotesize}
Both event-based approaches send all requests, install a series of one-shot Both event-based approaches send all requests, install a series of one-shot
handlers, and then return from the implementing function. In contrast, the handlers, and then return from the implementing function. In contrast, the
......
...@@ -103,7 +103,7 @@ because the actor objects themselves can get destroyed independently from their ...@@ -103,7 +103,7 @@ because the actor objects themselves can get destroyed independently from their
control block. A weak reference is only formed by \lstinline^actor_addr^ control block. A weak reference is only formed by \lstinline^actor_addr^
\see{actor-address}. \see{actor-address}.
\subsection{Converting Actor References with \texttt{actor\_cast}} \subsection{Converting Actor References with \lstinline^actor_cast^}
\label{actor-cast} \label{actor-cast}
The function \lstinline^actor_cast^ converts between actor pointers and The function \lstinline^actor_cast^ converts between actor pointers and
......
...@@ -124,20 +124,20 @@ User Manual\\ ...@@ -124,20 +124,20 @@ User Manual\\
\newcommand{\cppexample}[2][]{% \newcommand{\cppexample}[2][]{%
\ifthenelse{\isempty{#1}}% \ifthenelse{\isempty{#1}}%
{\lstinputlisting{../../examples/#2.cpp}}% {\lstinputlisting{\cafroot/examples/#2.cpp}}%
{\lstinputlisting[language=C++,linerange={#1}]{../../examples/#2.cpp}}% {\lstinputlisting[language=C++,linerange={#1}]{\cafroot/examples/#2.cpp}}%
} }
\newcommand{\iniexample}[2][]{% \newcommand{\iniexample}[2][]{%
\ifthenelse{\isempty{#1}}% \ifthenelse{\isempty{#1}}%
{\lstinputlisting[language=ini]{../../examples/#2.ini}}% {\lstinputlisting[language=ini]{\cafroot/examples/#2.ini}}%
{\lstinputlisting[language=ini,linerange={#1}]{../../examples/#2.ini}}% {\lstinputlisting[language=ini,linerange={#1}]{\cafroot/examples/#2.ini}}%
} }
\newcommand{\sourcefile}[2][]{% \newcommand{\sourcefile}[2][]{%
\ifthenelse{\isempty{#1}}% \ifthenelse{\isempty{#1}}%
{\lstinputlisting[language=C++]{../../#2}}% {\lstinputlisting[language=C++]{\cafroot/#2}}%
{\lstinputlisting[language=C++,linerange={#1}]{../../#2}}% {\lstinputlisting[language=C++,linerange={#1}]{\cafroot/#2}}%
} }
% highlight for INI file syntax % highlight for INI file syntax
......
...@@ -39,22 +39,48 @@ ...@@ -39,22 +39,48 @@
namespace caf { namespace caf {
namespace detail { namespace detail {
template <class T0, typename T1 = unit_t, typename T2 = unit_t, template <class T0 = unit_t, class T1 = unit_t, class T2 = unit_t,
typename T3 = unit_t, typename T4 = unit_t, typename T5 = unit_t, class T3 = unit_t, class T4 = unit_t, class T5 = unit_t,
typename T6 = unit_t, typename T7 = unit_t, typename T8 = unit_t, class T6 = unit_t, class T7 = unit_t, class T8 = unit_t,
typename T9 = unit_t, typename T10 = unit_t, typename T11 = unit_t, class T9 = unit_t, class T10 = unit_t, class T11 = unit_t,
typename T12 = unit_t, typename T13 = unit_t, typename T14 = unit_t, class T12 = unit_t, class T13 = unit_t, class T14 = unit_t,
typename T15 = unit_t, typename T16 = unit_t, typename T17 = unit_t, class T15 = unit_t, class T16 = unit_t, class T17 = unit_t,
typename T18 = unit_t, typename T19 = unit_t, typename T20 = unit_t> class T18 = unit_t, class T19 = unit_t, class T20 = unit_t,
class T21 = unit_t, class T22 = unit_t, class T23 = unit_t,
class T24 = unit_t, class T25 = unit_t, class T26 = unit_t,
class T27 = unit_t, class T28 = unit_t, class T29 = unit_t>
struct variant_data { struct variant_data {
union { union {
T0 v0; T1 v1; T2 v2; T0 v0;
T3 v3; T4 v4; T5 v5; T1 v1;
T6 v6; T7 v7; T8 v8; T2 v2;
T9 v9; T10 v10; T11 v11; T3 v3;
T12 v12; T13 v13; T14 v14; T4 v4;
T15 v15; T16 v16; T17 v17; T5 v5;
T18 v18; T19 v19; T20 v20; T6 v6;
T7 v7;
T8 v8;
T9 v9;
T10 v10;
T11 v11;
T12 v12;
T13 v13;
T14 v14;
T15 v15;
T16 v16;
T17 v17;
T18 v18;
T19 v19;
T20 v20;
T21 v21;
T22 v22;
T23 v23;
T24 v24;
T25 v25;
T26 v26;
T27 v27;
T28 v28;
T29 v29;
}; };
variant_data() { variant_data() {
...@@ -86,6 +112,15 @@ struct variant_data { ...@@ -86,6 +112,15 @@ struct variant_data {
CAF_VARIANT_DATA_GETTER(18) CAF_VARIANT_DATA_GETTER(18)
CAF_VARIANT_DATA_GETTER(19) CAF_VARIANT_DATA_GETTER(19)
CAF_VARIANT_DATA_GETTER(20) CAF_VARIANT_DATA_GETTER(20)
CAF_VARIANT_DATA_GETTER(21)
CAF_VARIANT_DATA_GETTER(22)
CAF_VARIANT_DATA_GETTER(23)
CAF_VARIANT_DATA_GETTER(24)
CAF_VARIANT_DATA_GETTER(25)
CAF_VARIANT_DATA_GETTER(26)
CAF_VARIANT_DATA_GETTER(27)
CAF_VARIANT_DATA_GETTER(28)
CAF_VARIANT_DATA_GETTER(29)
}; };
struct variant_data_destructor { struct variant_data_destructor {
......
...@@ -146,7 +146,7 @@ public: ...@@ -146,7 +146,7 @@ public:
// -- sanity checks ---------------------------------------------------------- // -- sanity checks ----------------------------------------------------------
static_assert(sizeof...(Ts) <= 20, "Too many template arguments given."); static_assert(sizeof...(Ts) <= 30, "Too many template arguments given.");
static_assert(sizeof...(Ts) > 0, "No template argument given."); static_assert(sizeof...(Ts) > 0, "No template argument given.");
...@@ -284,6 +284,16 @@ public: ...@@ -284,6 +284,16 @@ public:
CAF_VARIANT_CASE(17); CAF_VARIANT_CASE(17);
CAF_VARIANT_CASE(18); CAF_VARIANT_CASE(18);
CAF_VARIANT_CASE(19); CAF_VARIANT_CASE(19);
CAF_VARIANT_CASE(20);
CAF_VARIANT_CASE(21);
CAF_VARIANT_CASE(22);
CAF_VARIANT_CASE(23);
CAF_VARIANT_CASE(24);
CAF_VARIANT_CASE(25);
CAF_VARIANT_CASE(26);
CAF_VARIANT_CASE(27);
CAF_VARIANT_CASE(28);
CAF_VARIANT_CASE(29);
} }
} }
...@@ -481,6 +491,16 @@ inspect(Inspector& f, variant_writer<variant<Ts...>>& x) { ...@@ -481,6 +491,16 @@ inspect(Inspector& f, variant_writer<variant<Ts...>>& x) {
CAF_VARIANT_ASSIGN_CASE(17); CAF_VARIANT_ASSIGN_CASE(17);
CAF_VARIANT_ASSIGN_CASE(18); CAF_VARIANT_ASSIGN_CASE(18);
CAF_VARIANT_ASSIGN_CASE(19); CAF_VARIANT_ASSIGN_CASE(19);
CAF_VARIANT_ASSIGN_CASE(20);
CAF_VARIANT_ASSIGN_CASE(21);
CAF_VARIANT_ASSIGN_CASE(22);
CAF_VARIANT_ASSIGN_CASE(23);
CAF_VARIANT_ASSIGN_CASE(24);
CAF_VARIANT_ASSIGN_CASE(25);
CAF_VARIANT_ASSIGN_CASE(26);
CAF_VARIANT_ASSIGN_CASE(27);
CAF_VARIANT_ASSIGN_CASE(28);
CAF_VARIANT_ASSIGN_CASE(29);
} }
} }
......
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