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
086d5127
Commit
086d5127
authored
Feb 16, 2015
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve documentation of `message`
parent
3935def8
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
211 additions
and
129 deletions
+211
-129
libcaf_core/caf/message.hpp
libcaf_core/caf/message.hpp
+187
-129
libcaf_core/src/message.cpp
libcaf_core/src/message.cpp
+24
-0
No files found.
libcaf_core/caf/message.hpp
View file @
086d5127
...
@@ -42,24 +42,13 @@ namespace caf {
...
@@ -42,24 +42,13 @@ namespace caf {
class
message_handler
;
class
message_handler
;
/**
/**
* Describes a fixed-length copy-on-write tuple with elements of any type.
* Describes a fixed-length, copy-on-write, type-erased
* tuple with elements of any type.
*/
*/
class
message
{
class
message
{
public:
public:
/**
* A raw pointer to the data.
*/
using
raw_ptr
=
detail
::
message_data
*
;
/**
/**
* A (COW) smart pointer to the data.
* Creates an empty message.
*/
using
data_ptr
=
detail
::
message_data
::
ptr
;
/**
* Creates an empty tuple.
*/
*/
message
()
=
default
;
message
()
=
default
;
...
@@ -84,7 +73,7 @@ class message {
...
@@ -84,7 +73,7 @@ class message {
message
&
operator
=
(
const
message
&
)
=
default
;
message
&
operator
=
(
const
message
&
)
=
default
;
/**
/**
*
Gets the size of this tupl
e.
*
Returns the size of this messag
e.
*/
*/
inline
size_t
size
()
const
{
inline
size_t
size
()
const
{
return
m_vals
?
m_vals
->
size
()
:
0
;
return
m_vals
?
m_vals
->
size
()
:
0
;
...
@@ -115,21 +104,24 @@ class message {
...
@@ -115,21 +104,24 @@ class message {
}
}
/**
/**
* Creates a new message of size `n` starting at
element `pos
`.
* Creates a new message of size `n` starting at
the element at position `p
`.
*/
*/
message
slice
(
size_t
p
os
,
size_t
n
)
const
;
message
slice
(
size_t
p
,
size_t
n
)
const
;
/**
/**
*
Gets a mutable pointer to the element at position @p p
.
*
Returns a mutable pointer to the element at position `p`
.
*/
*/
void
*
mutable_at
(
size_t
p
);
void
*
mutable_at
(
size_t
p
);
/**
/**
*
Gets a const pointer to the element at position @p p
.
*
Returns a const pointer to the element at position `p`
.
*/
*/
const
void
*
at
(
size_t
p
)
const
;
const
void
*
at
(
size_t
p
)
const
;
const
char
*
uniform_name_at
(
size_t
pos
)
const
;
/**
* Returns the uniform type name for the element at position `p`.
*/
const
char
*
uniform_name_at
(
size_t
p
)
const
;
/**
/**
* Returns @c true if `*this == other, otherwise false.
* Returns @c true if `*this == other, otherwise false.
...
@@ -144,59 +136,59 @@ class message {
...
@@ -144,59 +136,59 @@ class message {
}
}
/**
/**
* Returns the value at
@p as instance of @p T
.
* Returns the value at
position `p` as const reference of type `T`
.
*/
*/
template
<
class
T
>
template
<
class
T
>
inline
const
T
&
get_as
(
size_t
p
)
const
{
const
T
&
get_as
(
size_t
p
)
const
{
CAF_REQUIRE
(
match_element
(
p
,
detail
::
type_nr
<
T
>::
value
,
&
typeid
(
T
)));
CAF_REQUIRE
(
match_element
(
p
,
detail
::
type_nr
<
T
>::
value
,
&
typeid
(
T
)));
return
*
reinterpret_cast
<
const
T
*>
(
at
(
p
));
return
*
reinterpret_cast
<
const
T
*>
(
at
(
p
));
}
}
/**
/**
* Returns the value at
@p as mutable data_ptr& of type @p T&
.
* Returns the value at
position `p` as mutable reference of type `T`
.
*/
*/
template
<
class
T
>
template
<
class
T
>
inline
T
&
get_as_mutable
(
size_t
p
)
{
T
&
get_as_mutable
(
size_t
p
)
{
CAF_REQUIRE
(
match_element
(
p
,
detail
::
type_nr
<
T
>::
value
,
&
typeid
(
T
)));
CAF_REQUIRE
(
match_element
(
p
,
detail
::
type_nr
<
T
>::
value
,
&
typeid
(
T
)));
return
*
reinterpret_cast
<
T
*>
(
mutable_at
(
p
));
return
*
reinterpret_cast
<
T
*>
(
mutable_at
(
p
));
}
}
/**
/**
* Returns a copy-on-write pointer to the internal data.
* Returns `handler(*this)`.
*/
inline
data_ptr
&
vals
()
{
return
m_vals
;
}
/**
* Returns a const copy-on-write pointer to the internal data.
*/
inline
const
data_ptr
&
vals
()
const
{
return
m_vals
;
}
/**
* Returns a const copy-on-write pointer to the internal data.
*/
inline
const
data_ptr
&
cvals
()
const
{
return
m_vals
;
}
/**
* Checks whether this message is dynamically typed, i.e.,
* its types were not known at compile time.
*/
bool
dynamically_typed
()
const
;
/**
* Applies `handler` to this message and returns the result
* of `handler(*this)`.
*/
*/
optional
<
message
>
apply
(
message_handler
handler
);
optional
<
message
>
apply
(
message_handler
handler
);
/**
/**
* Returns a new message consisting of all elements that were *not*
* Filters this message by applying slices of it to `handler` and returns
* matched by `handler`.
* the remaining elements of this operation. Slices are generated in the
* sequence `[0, size)`, `[0, size-1)`, `...` , `[1, size-1)`, `...`,
* `[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:
*
* ~~~
* 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));
* ~~~
*
* Step-by-step explanation:
* - Slice 1: `(1, 2.f, 3.f, 4)`, no match
* - Slice 2: `(1, 2.f, 3.f)`, no match
* - Slice 3: `(1, 2.f)`, no match
* - Slice 4: `(1)`, no match
* - Slice 5: `(2.f, 3.f, 4)`, no match
* - Slice 6: `(2.f, 3.f)`, *match*; new message is `(1, 4)`
* - Slice 7: `(4)`, no match
*
* Slice 7 is `(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.
*/
*/
message
filter
(
message_handler
handler
)
const
;
message
filter
(
message_handler
handler
)
const
;
...
@@ -205,76 +197,94 @@ class message {
...
@@ -205,76 +197,94 @@ class message {
* along with a description and a callback.
* along with a description and a callback.
*/
*/
struct
cli_arg
{
struct
cli_arg
{
/**
* Full name of this CLI argument using format "<long name>[,<short name>]"
*/
std
::
string
name
;
std
::
string
name
;
/**
* Desciption of this CLI argument for the auto-generated help text.
*/
std
::
string
text
;
std
::
string
text
;
/**
* Returns `true` on a match, `false` otherwise.
*/
std
::
function
<
bool
(
const
std
::
string
&
)
>
fun
;
std
::
function
<
bool
(
const
std
::
string
&
)
>
fun
;
inline
cli_arg
(
std
::
string
nstr
,
std
::
string
tstr
)
:
name
(
std
::
move
(
nstr
)),
/**
text
(
std
::
move
(
tstr
))
{
* Creates a CLI argument without data.
// nop
*/
}
cli_arg
(
std
::
string
name
,
std
::
string
text
);
inline
cli_arg
(
std
::
string
nstr
,
std
::
string
tstr
,
std
::
string
&
arg
)
:
name
(
std
::
move
(
nstr
)),
/**
text
(
std
::
move
(
tstr
))
{
* Creates a CLI argument storing its matched argument in `dest`.
fun
=
[
&
arg
](
const
std
::
string
&
str
)
->
bool
{
*/
arg
=
str
;
cli_arg
(
std
::
string
name
,
std
::
string
text
,
std
::
string
&
dest
);
return
true
;
};
/**
}
* Creates a CLI argument appending matched arguments to `dest`.
inline
cli_arg
(
std
::
string
nstr
,
std
::
string
tstr
,
std
::
vector
<
std
::
string
>&
arg
)
*/
:
name
(
std
::
move
(
nstr
)),
cli_arg
(
std
::
string
name
,
std
::
string
text
,
std
::
vector
<
std
::
string
>&
dest
);
text
(
std
::
move
(
tstr
))
{
fun
=
[
&
arg
](
const
std
::
string
&
str
)
->
bool
{
/**
arg
.
push_back
(
str
);
* Creates a CLI argument for converting from strings,
return
true
;
* storing its matched argument in `dest`.
};
*/
}
template
<
class
T
>
template
<
class
T
>
cli_arg
(
std
::
string
nstr
,
std
::
string
tstr
,
T
&
arg
)
cli_arg
(
std
::
string
name
,
std
::
string
text
,
T
&
dest
);
:
name
(
std
::
move
(
nstr
)),
text
(
std
::
move
(
tstr
))
{
/**
fun
=
[
&
arg
](
const
std
::
string
&
str
)
->
bool
{
* Creates a CLI argument for converting from strings,
auto
res
=
from_string
<
T
>
(
str
);
* appending matched arguments to `dest`.
if
(
!
res
)
{
*/
return
false
;
}
arg
=
*
res
;
return
true
;
};
}
template
<
class
T
>
template
<
class
T
>
cli_arg
(
std
::
string
nstr
,
std
::
string
tstr
,
std
::
vector
<
T
>&
arg
)
cli_arg
(
std
::
string
name
,
std
::
string
text
,
std
::
vector
<
T
>&
dest
);
:
name
(
std
::
move
(
nstr
)),
text
(
std
::
move
(
tstr
))
{
fun
=
[
&
arg
](
const
std
::
string
&
str
)
->
bool
{
auto
res
=
from_string
<
T
>
(
str
);
if
(
!
res
)
{
return
false
;
}
arg
.
push_back
(
*
res
);
return
true
;
};
}
};
};
struct
cli_res
;
struct
cli_res
;
/**
/**
* A simplistic interface for using `filter` to parse command line options.
* A simplistic interface for using `filter` to parse command line options.
* Usage example:
*
* ~~~
* 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 ...
* }
* // ...
* }
* ~~~
*/
*/
cli_res
filter_cli
(
std
::
vector
<
cli_arg
>
args
)
const
;
cli_res
filter_cli
(
std
::
vector
<
cli_arg
>
args
)
const
;
/**
/**
* Queries whether the element at `pos` is of type `T`.
* Queries whether the element at position `p` is of type `T`.
* @param pos Index of element in question.
*/
*/
template
<
class
T
>
template
<
class
T
>
bool
match_element
(
size_t
p
os
)
const
{
bool
match_element
(
size_t
p
)
const
{
const
std
::
type_info
*
rtti
=
nullptr
;
const
std
::
type_info
*
rtti
=
nullptr
;
if
(
detail
::
type_nr
<
T
>::
value
==
0
)
{
if
(
detail
::
type_nr
<
T
>::
value
==
0
)
{
rtti
=
&
typeid
(
T
);
rtti
=
&
typeid
(
T
);
}
}
return
match_element
(
p
os
,
detail
::
type_nr
<
T
>::
value
,
rtti
);
return
match_element
(
p
,
detail
::
type_nr
<
T
>::
value
,
rtti
);
}
}
/**
/**
...
@@ -287,9 +297,30 @@ class message {
...
@@ -287,9 +297,30 @@ class message {
return
size
()
==
sizeof
...(
Ts
)
&&
match_elements_impl
(
p0
,
tlist
);
return
size
()
==
sizeof
...(
Ts
)
&&
match_elements_impl
(
p0
,
tlist
);
}
}
/** @cond PRIVATE */
/** @cond PRIVATE */
using
raw_ptr
=
detail
::
message_data
*
;
using
data_ptr
=
detail
::
message_data
::
ptr
;
explicit
message
(
raw_ptr
);
explicit
message
(
const
data_ptr
&
vals
);
void
reset
();
inline
data_ptr
&
vals
()
{
return
m_vals
;
}
inline
const
data_ptr
&
vals
()
const
{
return
m_vals
;
}
inline
const
data_ptr
&
cvals
()
const
{
return
m_vals
;
}
inline
uint32_t
type_token
()
const
{
inline
uint32_t
type_token
()
const
{
return
m_vals
?
m_vals
->
type_token
()
:
0xFFFFFFFF
;
return
m_vals
?
m_vals
->
type_token
()
:
0xFFFFFFFF
;
}
}
...
@@ -298,16 +329,10 @@ class message {
...
@@ -298,16 +329,10 @@ class message {
m_vals
.
detach
();
m_vals
.
detach
();
}
}
void
reset
();
explicit
message
(
raw_ptr
);
inline
std
::
string
tuple_type_names
()
const
{
inline
std
::
string
tuple_type_names
()
const
{
return
m_vals
->
tuple_type_names
();
return
m_vals
->
tuple_type_names
();
}
}
explicit
message
(
const
data_ptr
&
vals
);
struct
move_from_tuple_helper
{
struct
move_from_tuple_helper
{
template
<
class
...
Ts
>
template
<
class
...
Ts
>
inline
message
operator
()(
Ts
&
...
vs
)
{
inline
message
operator
()(
Ts
&
...
vs
)
{
...
@@ -321,14 +346,7 @@ class message {
...
@@ -321,14 +346,7 @@ class message {
return
detail
::
apply_args
(
f
,
detail
::
get_indices
(
tup
),
tup
);
return
detail
::
apply_args
(
f
,
detail
::
get_indices
(
tup
),
tup
);
}
}
/**
bool
match_element
(
size_t
p
,
uint16_t
tnr
,
const
std
::
type_info
*
rtti
)
const
;
* Tries to match element at position `pos` to given RTTI.
* @param pos Index of element in question.
* @param typenr Number of queried type or `0` for custom types.
* @param rtti Queried type or `nullptr` for builtin types.
*/
bool
match_element
(
size_t
pos
,
uint16_t
typenr
,
const
std
::
type_info
*
rtti
)
const
;
template
<
class
T
,
class
...
Ts
>
template
<
class
T
,
class
...
Ts
>
bool
match_elements
(
detail
::
type_list
<
T
,
Ts
...
>
list
)
const
{
bool
match_elements
(
detail
::
type_list
<
T
,
Ts
...
>
list
)
const
{
...
@@ -344,15 +362,17 @@ class message {
...
@@ -344,15 +362,17 @@ class message {
detail
::
type_list
<>
)
const
{
detail
::
type_list
<>
)
const
{
return
true
;
// end of recursion
return
true
;
// end of recursion
}
}
template
<
size_t
P
,
class
T
,
class
...
Ts
>
template
<
size_t
P
,
class
T
,
class
...
Ts
>
bool
match_elements_impl
(
std
::
integral_constant
<
size_t
,
P
>
,
bool
match_elements_impl
(
std
::
integral_constant
<
size_t
,
P
>
,
detail
::
type_list
<
T
,
Ts
...
>
)
const
{
detail
::
type_list
<
T
,
Ts
...
>
)
const
{
std
::
integral_constant
<
size_t
,
P
+
1
>
next_p
;
std
::
integral_constant
<
size_t
,
P
+
1
>
next_p
;
detail
::
type_list
<
Ts
...
>
next_list
;
detail
::
type_list
<
Ts
...
>
next_list
;
return
match_element
<
T
>
(
P
)
return
match_element
<
T
>
(
P
)
&&
match_elements_impl
(
next_p
,
next_list
);
&&
match_elements_impl
(
next_p
,
next_list
);
}
}
message
filter_impl
(
size_t
start
,
message_handler
handler
)
const
;
message
filter_impl
(
size_t
start
,
message_handler
handler
)
const
;
data_ptr
m_vals
;
data_ptr
m_vals
;
};
};
...
@@ -364,10 +384,12 @@ struct message::cli_res {
...
@@ -364,10 +384,12 @@ struct message::cli_res {
* Stores the remaining (unmatched) arguments.
* Stores the remaining (unmatched) arguments.
*/
*/
message
remainder
;
message
remainder
;
/**
/**
* Stores the names of all active options.
* Stores the names of all active options.
*/
*/
std
::
set
<
std
::
string
>
opts
;
std
::
set
<
std
::
string
>
opts
;
/**
/**
* Stores the automatically generated help text.
* Stores the automatically generated help text.
*/
*/
...
@@ -388,6 +410,10 @@ inline bool operator!=(const message& lhs, const message& rhs) {
...
@@ -388,6 +410,10 @@ inline bool operator!=(const message& lhs, const message& rhs) {
return
!
(
lhs
==
rhs
);
return
!
(
lhs
==
rhs
);
}
}
/**
* Unboxes atom constants, i.e., converts `atom_constant<V>` to `V`.
* @relates message
*/
template
<
class
T
>
template
<
class
T
>
struct
unbox_message_element
{
struct
unbox_message_element
{
using
type
=
T
;
using
type
=
T
;
...
@@ -399,24 +425,24 @@ struct unbox_message_element<atom_constant<V>> {
...
@@ -399,24 +425,24 @@ struct unbox_message_element<atom_constant<V>> {
};
};
/**
/**
*
Creates a new `message` containing the elements `args...
`.
*
Returns a new `message` containing the values `(v, vs...)
`.
* @relates message
* @relates message
*/
*/
template
<
class
T
,
class
...
T
s
>
template
<
class
V
,
class
...
V
s
>
typename
std
::
enable_if
<
typename
std
::
enable_if
<
!
std
::
is_same
<
message
,
typename
std
::
decay
<
T
>::
type
>::
value
!
std
::
is_same
<
message
,
typename
std
::
decay
<
V
>::
type
>::
value
||
(
sizeof
...(
T
s
)
>
0
),
||
(
sizeof
...(
V
s
)
>
0
),
message
message
>::
type
>::
type
make_message
(
T
&&
arg
,
Ts
&&
...
arg
s
)
{
make_message
(
V
&&
v
,
Vs
&&
...
v
s
)
{
using
storage
using
storage
=
detail
::
tuple_vals
<
typename
unbox_message_element
<
=
detail
::
tuple_vals
<
typename
unbox_message_element
<
typename
detail
::
strip_and_convert
<
T
>::
type
typename
detail
::
strip_and_convert
<
V
>::
type
>::
type
,
>::
type
,
typename
unbox_message_element
<
typename
unbox_message_element
<
typename
detail
::
strip_and_convert
<
T
s
>::
type
typename
detail
::
strip_and_convert
<
V
s
>::
type
>::
type
...
>
;
>::
type
...
>
;
auto
ptr
=
new
storage
(
std
::
forward
<
T
>
(
arg
),
std
::
forward
<
Ts
>
(
arg
s
)...);
auto
ptr
=
new
storage
(
std
::
forward
<
V
>
(
v
),
std
::
forward
<
Vs
>
(
v
s
)...);
return
message
{
detail
::
message_data
::
ptr
{
ptr
}};
return
message
{
detail
::
message_data
::
ptr
{
ptr
}};
}
}
...
@@ -428,6 +454,38 @@ inline message make_message(message other) {
...
@@ -428,6 +454,38 @@ inline message make_message(message other) {
return
std
::
move
(
other
);
return
std
::
move
(
other
);
}
}
/******************************************************************************
* template member function implementations *
******************************************************************************/
template
<
class
T
>
message
::
cli_arg
::
cli_arg
(
std
::
string
nstr
,
std
::
string
tstr
,
T
&
arg
)
:
name
(
std
::
move
(
nstr
)),
text
(
std
::
move
(
tstr
))
{
fun
=
[
&
arg
](
const
std
::
string
&
str
)
->
bool
{
auto
res
=
from_string
<
T
>
(
str
);
if
(
!
res
)
{
return
false
;
}
arg
=
*
res
;
return
true
;
};
}
template
<
class
T
>
message
::
cli_arg
::
cli_arg
(
std
::
string
nstr
,
std
::
string
tstr
,
std
::
vector
<
T
>&
arg
)
:
name
(
std
::
move
(
nstr
)),
text
(
std
::
move
(
tstr
))
{
fun
=
[
&
arg
](
const
std
::
string
&
str
)
->
bool
{
auto
res
=
from_string
<
T
>
(
str
);
if
(
!
res
)
{
return
false
;
}
arg
.
push_back
(
*
res
);
return
true
;
};
}
}
// namespace caf
}
// namespace caf
#endif // CAF_MESSAGE_HPP
#endif // CAF_MESSAGE_HPP
libcaf_core/src/message.cpp
View file @
086d5127
...
@@ -264,4 +264,28 @@ message::cli_res message::filter_cli(std::vector<cli_arg> cliargs) const {
...
@@ -264,4 +264,28 @@ message::cli_res message::filter_cli(std::vector<cli_arg> cliargs) const {
return
{
res
,
std
::
move
(
opts
),
std
::
move
(
helptext
)};
return
{
res
,
std
::
move
(
opts
),
std
::
move
(
helptext
)};
}
}
message
::
cli_arg
::
cli_arg
(
std
::
string
nstr
,
std
::
string
tstr
)
:
name
(
std
::
move
(
nstr
)),
text
(
std
::
move
(
tstr
))
{
// nop
}
message
::
cli_arg
::
cli_arg
(
std
::
string
nstr
,
std
::
string
tstr
,
std
::
string
&
arg
)
:
name
(
std
::
move
(
nstr
)),
text
(
std
::
move
(
tstr
))
{
fun
=
[
&
arg
](
const
std
::
string
&
str
)
->
bool
{
arg
=
str
;
return
true
;
};
}
message
::
cli_arg
::
cli_arg
(
std
::
string
nstr
,
std
::
string
tstr
,
std
::
vector
<
std
::
string
>&
arg
)
:
name
(
std
::
move
(
nstr
)),
text
(
std
::
move
(
tstr
))
{
fun
=
[
&
arg
](
const
std
::
string
&
str
)
->
bool
{
arg
.
push_back
(
str
);
return
true
;
};
}
}
// namespace caf
}
// namespace caf
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