Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
Actor Framework
Commits
1a35bf3b
Commit
1a35bf3b
authored
Nov 06, 2019
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'issue/956'
parents
1b1aae99
18e800a8
Changes
13
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
1458 additions
and
141 deletions
+1458
-141
.clang-format
.clang-format
+2
-0
CMakeLists.txt
CMakeLists.txt
+0
-5
doc/CMakeLists.txt
doc/CMakeLists.txt
+51
-56
doc/cmake/caf-generate-rst.cpp
doc/cmake/caf-generate-rst.cpp
+1272
-0
doc/cmake/variables.tex.in
doc/cmake/variables.tex.in
+1
-0
doc/tex/Brokers.tex
doc/tex/Brokers.tex
+1
-1
doc/tex/CommonPitfalls.tex
doc/tex/CommonPitfalls.tex
+45
-52
doc/tex/Introduction.tex
doc/tex/Introduction.tex
+1
-1
doc/tex/MessagePassing.tex
doc/tex/MessagePassing.tex
+8
-4
doc/tex/ReferenceCounting.tex
doc/tex/ReferenceCounting.tex
+1
-1
doc/tex/manual.tex
doc/tex/manual.tex
+6
-6
libcaf_core/caf/detail/variant_data.hpp
libcaf_core/caf/detail/variant_data.hpp
+49
-14
libcaf_core/caf/variant.hpp
libcaf_core/caf/variant.hpp
+21
-1
No files found.
.clang-format
View file @
1a35bf3b
...
...
@@ -32,6 +32,8 @@ IndentWidth: 2
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
Language: Cpp
MacroBlockBegin: "^BEGIN_STATE$"
MacroBlockEnd: "^END_STATE$"
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
PenaltyBreakAssignment: 1000
...
...
CMakeLists.txt
View file @
1a35bf3b
...
...
@@ -654,11 +654,6 @@ message(STATUS "Set release version for all documentation to ${CAF_RELEASE}.")
# -- 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
)
################################################################################
...
...
doc/CMakeLists.txt
View file @
1a35bf3b
cmake_minimum_required
(
VERSION 2.8.12
)
project
(
doc NONE
)
add_custom_target
(
doc
)
# -- list all .tex source files ------------------------------------------------
...
...
@@ -34,20 +30,22 @@ set(sources
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"
"
${
CMAKE_CURRENT_BINARY_DIR
}
/Doxyfile"
@ONLY
)
file
(
MAKE_DIRECTORY
"
${
CMAKE_CURRENT_BINARY_DIR
}
/tex"
)
configure_file
(
"cmake/variables.tex.in"
"
${
CMAKE_CURRENT_BINARY_DIR
}
/tex/variables.tex"
@ONLY
)
file
(
MAKE_DIRECTORY
"
${
CMAKE_CURRENT_BINARY_DIR
}
/rst"
)
configure_file
(
"cmake/conf.py.in"
"
${
CMAKE_CURRENT_BINARY_DIR
}
/rst/conf.py"
@ONLY
)
...
...
@@ -60,6 +58,50 @@ configure_file("cmake/index_header.rst.in"
"
${
CMAKE_CURRENT_BINARY_DIR
}
/rst/index_header.rst"
@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 -------------------------------------------------------------
find_package
(
Doxygen
)
...
...
@@ -76,23 +118,6 @@ else()
add_dependencies
(
doc doxygen
)
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 ---------------------------------------------------------------
if
(
CAF_BUILD_TEX_MANUAL
)
...
...
@@ -108,35 +133,5 @@ if (CAF_BUILD_TEX_MANUAL)
FORCE_PDF
TARGET_NAME 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
()
doc/cmake/caf-generate-rst.cpp
0 → 100644
View file @
1a35bf3b
This diff is collapsed.
Click to expand it.
doc/cmake/variables.tex.in
View file @
1a35bf3b
\newcommand{\cafrelease}{@CAF_RELEASE@}
\newcommand{\cafsha}{@CAF_SHA@}
\newcommand{\cafroot}{@PROJECT_SOURCE_DIR@}
doc/tex/Brokers.tex
View file @
1a35bf3b
...
...
@@ -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
server.
\subsection
{
Class
\
texttt
{
broker
}
}
\subsection
{
Class
\
lstinline
^
broker
^
}
\label
{
broker-class
}
\begin{lstlisting}
...
...
doc/tex/CommonPitfalls.tex
View file @
1a35bf3b
...
...
@@ -6,66 +6,59 @@ programming in CAF.
\subsection
{
Defining Message Handlers
}
\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)
{
/*...*/
}
}
;
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:
message
_
handler ok2;
// some place later
ok2.assign(
[](int i)
{
/*...*/
}
,
[](float f)
{
/*...*/
}
);
\end{lstlisting}
\end{itemize}
\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}
\subsection
{
Event-Based API
}
\begin{itemize}
\item
The member function
\lstinline
^
become
^
does not block, i.e., always
returns immediately. Thus, lambda expressions should
\textit
{
always
}
capture
by value. Otherwise, all references on the stack will cause undefined
behavior if the lambda expression is executed.
\end{itemize}
The member function
\lstinline
^
become
^
does not block, i.e., always returns
immediately. Thus, lambda expressions should
\textit
{
always
}
capture by value.
Otherwise, all references on the stack will cause undefined behavior if the
lambda expression is executed.
\subsection
{
Requests
}
\begin{itemize}
\item
A handle returned by
\lstinline
^
request
^
represents
\emph
{
exactly one
}
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}
A handle returned by
\lstinline
^
request
^
represents
\emph
{
exactly one
}
response
message. It is not possible to receive more than one response message.
\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
}
\begin{itemize}
\item
It is strongly recommended to
\textbf
{
not
}
share states between actors.
In particular, no actor shall ever access member variables or member
functions of another actor. Accessing shared memory segments concurrently
can cause undefined behavior that is incredibly hard to find and debug.
However, sharing
\textit
{
data
}
between actors is fine, as long as the data
is
\textit
{
immutable
}
and its lifetime is guaranteed to outlive all actors.
The simplest way to meet the lifetime guarantee is by storing the data in
smart pointers such as
\lstinline
^
std::shared
_
ptr
^
. Nevertheless, the
recommended way of sharing informations is message passing. Sending the
same message to multiple actors does not result in copying the data several
times.
\end{itemize}
It is strongly recommended to
\textbf
{
not
}
share states between actors. In
particular, no actor shall ever access member variables or member functions of
another actor. Accessing shared memory segments concurrently can cause undefined
behavior that is incredibly hard to find and debug. However, sharing
\textit
{
data
}
between actors is fine, as long as the data is
\textit
{
immutable
}
and its lifetime is guaranteed to outlive all actors. The simplest way to meet
the lifetime guarantee is by storing the data in smart pointers such as
\lstinline
^
std::shared
_
ptr
^
. Nevertheless, the recommended way of sharing
informations is message passing. Sending the same message to multiple actors
does not result in copying the data several times.
doc/tex/Introduction.tex
View file @
1a35bf3b
...
...
@@ -98,7 +98,7 @@ knowing the proper handle type. Pointers must be converted to a handle via
\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
}
\label
{
monitor
}
...
...
doc/tex/MessagePassing.tex
View file @
1a35bf3b
...
...
@@ -153,13 +153,15 @@ When passing the \lstinline^cells^ vector to our three different
implementations, we observe three outputs. Our
\lstinline
^
waiting
_
testee
^
actor
will always print:
{
\footnotesize
\begin{verbatim}
\begin{footnotesize}
\begin{verbatim}
cell #9 -> 16
cell #8 -> 9
cell #7 -> 4
cell #6 -> 1
cell #5 -> 0
\end{verbatim}
}
\end{verbatim}
\end{footnotesize}
This is because
\lstinline
^
await
^
puts the one-shots handlers onto a stack and
enforces LIFO order by re-ordering incoming response messages.
...
...
@@ -170,13 +172,15 @@ immediately.
Finally, the
\lstinline
^
blocking
_
testee
^
implementation will always print:
{
\footnotesize
\begin{verbatim}
\begin{footnotesize}
\begin{verbatim}
cell #5 -> 0
cell #6 -> 1
cell #7 -> 4
cell #8 -> 9
cell #9 -> 16
\end{verbatim}
}
\end{verbatim}
\end{footnotesize}
Both event-based approaches send all requests, install a series of one-shot
handlers, and then return from the implementing function. In contrast, the
...
...
doc/tex/ReferenceCounting.tex
View file @
1a35bf3b
...
...
@@ -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
^
\see
{
actor-address
}
.
\subsection
{
Converting Actor References with
\
texttt
{
actor
\_
cast
}
}
\subsection
{
Converting Actor References with
\
lstinline
^
actor
_
cast
^
}
\label
{
actor-cast
}
The function
\lstinline
^
actor
_
cast
^
converts between actor pointers and
...
...
doc/tex/manual.tex
View file @
1a35bf3b
...
...
@@ -124,20 +124,20 @@ User Manual\\
\newcommand
{
\cppexample
}
[2][]
{
%
\ifthenelse
{
\isempty
{
#1
}}
%
{
\lstinputlisting
{
../..
/examples/#2.cpp
}}
%
{
\lstinputlisting
[language=C++,linerange={#1}]
{
../..
/examples/#2.cpp
}}
%
{
\lstinputlisting
{
\cafroot
/examples/#2.cpp
}}
%
{
\lstinputlisting
[language=C++,linerange={#1}]
{
\cafroot
/examples/#2.cpp
}}
%
}
\newcommand
{
\iniexample
}
[2][]
{
%
\ifthenelse
{
\isempty
{
#1
}}
%
{
\lstinputlisting
[language=ini]
{
../..
/examples/#2.ini
}}
%
{
\lstinputlisting
[language=ini,linerange={#1}]
{
../..
/examples/#2.ini
}}
%
{
\lstinputlisting
[language=ini]
{
\cafroot
/examples/#2.ini
}}
%
{
\lstinputlisting
[language=ini,linerange={#1}]
{
\cafroot
/examples/#2.ini
}}
%
}
\newcommand
{
\sourcefile
}
[2][]
{
%
\ifthenelse
{
\isempty
{
#1
}}
%
{
\lstinputlisting
[language=C++]
{
../..
/#2
}}
%
{
\lstinputlisting
[language=C++,linerange={#1}]
{
../..
/#2
}}
%
{
\lstinputlisting
[language=C++]
{
\cafroot
/#2
}}
%
{
\lstinputlisting
[language=C++,linerange={#1}]
{
\cafroot
/#2
}}
%
}
% highlight for INI file syntax
...
...
libcaf_core/caf/detail/variant_data.hpp
View file @
1a35bf3b
...
...
@@ -39,22 +39,48 @@
namespace
caf
{
namespace
detail
{
template
<
class
T0
,
typename
T1
=
unit_t
,
typename
T2
=
unit_t
,
typename
T3
=
unit_t
,
typename
T4
=
unit_t
,
typename
T5
=
unit_t
,
typename
T6
=
unit_t
,
typename
T7
=
unit_t
,
typename
T8
=
unit_t
,
typename
T9
=
unit_t
,
typename
T10
=
unit_t
,
typename
T11
=
unit_t
,
typename
T12
=
unit_t
,
typename
T13
=
unit_t
,
typename
T14
=
unit_t
,
typename
T15
=
unit_t
,
typename
T16
=
unit_t
,
typename
T17
=
unit_t
,
typename
T18
=
unit_t
,
typename
T19
=
unit_t
,
typename
T20
=
unit_t
>
template
<
class
T0
=
unit_t
,
class
T1
=
unit_t
,
class
T2
=
unit_t
,
class
T3
=
unit_t
,
class
T4
=
unit_t
,
class
T5
=
unit_t
,
class
T6
=
unit_t
,
class
T7
=
unit_t
,
class
T8
=
unit_t
,
class
T9
=
unit_t
,
class
T10
=
unit_t
,
class
T11
=
unit_t
,
class
T12
=
unit_t
,
class
T13
=
unit_t
,
class
T14
=
unit_t
,
class
T15
=
unit_t
,
class
T16
=
unit_t
,
class
T17
=
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
{
union
{
T0
v0
;
T1
v1
;
T2
v2
;
T3
v3
;
T4
v4
;
T5
v5
;
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
;
T0
v0
;
T1
v1
;
T2
v2
;
T3
v3
;
T4
v4
;
T5
v5
;
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
()
{
...
...
@@ -86,6 +112,15 @@ struct variant_data {
CAF_VARIANT_DATA_GETTER
(
18
)
CAF_VARIANT_DATA_GETTER
(
19
)
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
{
...
...
libcaf_core/caf/variant.hpp
View file @
1a35bf3b
...
...
@@ -146,7 +146,7 @@ public:
// -- sanity checks ----------------------------------------------------------
static_assert
(
sizeof
...(
Ts
)
<=
2
0
,
"Too many template arguments given."
);
static_assert
(
sizeof
...(
Ts
)
<=
3
0
,
"Too many template arguments given."
);
static_assert
(
sizeof
...(
Ts
)
>
0
,
"No template argument given."
);
...
...
@@ -284,6 +284,16 @@ public:
CAF_VARIANT_CASE
(
17
);
CAF_VARIANT_CASE
(
18
);
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) {
CAF_VARIANT_ASSIGN_CASE
(
17
);
CAF_VARIANT_ASSIGN_CASE
(
18
);
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
);
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment