Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F10707421
Invoker.hpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Size
8 KB
Referenced Files
None
Subscribers
None
Invoker.hpp
View Options
/***************************************************************************//**
*
* \file rosa/core/Invoker.hpp
*
* \author David Juhasz (david.juhasz@tuwien.ac.at)
*
* \date 2017
*
* \brief Facilities for providing actual arguments for functions as
* `rosa::Message`objects.
*
******************************************************************************/
#ifndef ROSA_CORE_INVOKER_HPP
#define ROSA_CORE_INVOKER_HPP
#include
"rosa/core/MessageMatcher.hpp"
#include
"rosa/support/log.h"
#include
<functional>
#include
<memory>
namespace
rosa
{
/// Wraps a function and provides a simple interface to invoke the stored
/// function by passing actual arguments as a `rosa::Message` object.
///
/// \note A `rosa::Invoker` instance is supposed to be owned by a
/// `rosa::MessageHandler` instance, and not being used directly from user code.
class
Invoker
{
protected
:
/// Creates an instance.
///
/// \note Protected constructor restricts instantiation to derived classes.
Invoker
(
void
)
noexcept
;
public
:
/// Destroys `this` object.
virtual
~
Invoker
(
void
);
/// Possible results of an invocation.
enum
class
Result
{
NoMatch
,
///< The wrapped function could not be invoked
Invoked
///< The wrapped function has been invoked
};
/// Type alias for a smart-pointer for `rosa::Invoker`.
using
invoker_t
=
std
::
unique_ptr
<
const
Invoker
>
;
/// Type alias for `rosa::Invoker::Result`.
using
result_t
=
Result
;
/// Tells if a `rosa::Message` object can be used to invoke the function
/// wrapped in `this` object.
///
/// \param Msg `rosa::Message` to check
///
/// \return whether `Msg` can be used to invoke the wrapped function
virtual
bool
match
(
const
Message
&
Msg
)
const
noexcept
=
0
;
/// Tries to invoke the wrapped function with a `rosa::Message` object.
///
/// The wrapped function is invoked if the actual `rosa::Message` object can
/// be used to invoke it.
///
/// \param Msg `rosa::Message` to try to invoke the wrapped function with
///
/// \return whether the wrapped function could be invoked with `Msg`
virtual
result_t
operator
()(
const
Message
&
Msg
)
const
noexcept
=
0
;
/// Instantiates an implementation of `rosa::Invoker` with the given function.
///
/// \note As there is no empty `rosa::Message`, no `rosa::Invoker` wraps a
/// function without any argument.
///
/// \tparam T type of the first mandatory argument
/// \tparam Ts types of any further arguments
///
/// \param F function to wrap
///
/// \return new `invoker_t` object created from the given function
template
<
typename
T
,
typename
...
Ts
>
static
invoker_t
wrap
(
std
::
function
<
void
(
T
,
Ts
...)
noexcept
>
&&
F
)
noexcept
;
/// Convenience template alias for casting callable stuff to function objects
/// for wrapping.
///
/// \tparam Ts types of arguments
///
/// \todo Should make it possible to avoid using an explicit conversion for
/// the arguments of wrap.
template
<
typename
...
Ts
>
using
F
=
std
::
function
<
void
(
Ts
...)
noexcept
>
;
/// Convenience template for preparing non-static member functions into
/// function objects for wrapping.
///
/// \tparam C type whose non-static member the function is
/// \tparam Ts types of arguments
///
/// \see THISMEMBER
template
<
typename
C
,
typename
...
Ts
>
static
inline
F
<
Ts
...
>
M
(
C
*
O
,
void
(
C
::*
Fun
)(
Ts
...)
noexcept
)
noexcept
;
};
/// Convenience preprocessor macro for the typical use of `rosa::Invoker::M`. It
/// can be used inside a class to turn a non-static member function into a
/// function object capturing this pointer, so using the actual object when
/// handling a `rosa::Message`.
///
/// \param FUN the non-static member function to wrap
///
/// \note Inside the class `MyClass`, use\code
/// THISMEMBER(fun)
/// \endcode instead of\code
/// Invoker::M(this, &MyClass::fun)
/// \endcode
#define THISMEMBER(FUN) \
Invoker::M(this, &std::decay<decltype(*this)>::type::FUN)
/// Nested namespace with implementation of `rosa::Invoker` and helper
/// templates, consider it private.
namespace
{
/// \defgroup Seq
///
///@{
/// Template with an empty struct to store a sequence of numbers in compile time
/// as template arguments.
template
<
size_t
...
>
struct
Seq
{};
/// Sequence generator, the general case when counting down by extending the
/// sequence.
template
<
size_t
N
,
size_t
...
S
>
struct
GenSeq
:
GenSeq
<
N
-
1
,
N
-
1
,
S
...
>
{};
/// Sequence generator, the terminal case when storing the generated sequence
/// into `rosa::Seq`.
template
<
size_t
...
S
>
struct
GenSeq
<
0
,
S
...
>
{
using
Type
=
Seq
<
S
...
>
;
};
///@}
/// \defgroup InvokerImpl
///
/// Implements the `rosa::Invoker` interface for functions with different
/// signatures.
///
///@{
/// Declaration of `rosa::InvokerImpl` implementing `rosa::Invoker`.
///
/// \tparam Fun function to wrap
template
<
typename
Fun
>
class
InvokerImpl
;
/// Implementation of `rosa::InvokerImpl` for `std::function`.
///
/// \tparam T type of the first mandatory argument
/// \tparam Ts types of further arguments
///
/// \note As there is no empty `rosa::Message`, no `rosa::Invoker` wraps a
/// function without any argument, i.e., no std::function<void(void) noexcept>.
template
<
typename
T
,
typename
...
Ts
>
class
InvokerImpl
<
std
::
function
<
void
(
T
,
Ts
...)
noexcept
>>
final
:
public
Invoker
{
/// Type alias for the stored function.
using
function_t
=
std
::
function
<
void
(
T
,
Ts
...)
noexcept
>
;
/// Type alias for correctly typed argument-tuples as obtained from
/// `rosa::Message`.
using
args_t
=
std
::
tuple
<
const
T
&
,
const
Ts
&
...
>
;
/// Alias for `rosa::MessageMatcher` for the arguments of the stored function.
using
Matcher
=
MsgMatcher
<
T
,
Ts
...
>
;
/// The wrapped function.
const
function_t
F
;
/// Invokes `F` by unpacking arguments from a `std::tuple` with the help of
/// the actual template arguments.
///
/// \tparam S sequence of numbers indexing `std::tuple` for arguments
///
/// \param Args arguments to invoke `F` with
///
/// \pre the length of `S` and size of `Args` are matching:\code
/// sizeof...(S) == std::tuple_size<args_t>::value
/// \endcode
template
<
size_t
...
S
>
inline
void
invokeFunction
(
Seq
<
S
...
>
,
const
args_t
&
Args
)
const
noexcept
;
public
:
/// Creates an instance.
///
/// \param F function to wrap
///
/// \pre `F` is valid:\code
/// bool(F)
/// \endcode
InvokerImpl
(
function_t
&&
F
)
noexcept
:
F
(
F
)
{
ASSERT
(
bool
(
F
));
// Sanity check.
}
/// Destroys `this` object.
~
InvokerImpl
(
void
)
=
default
;
/// Tells if a `rosa::Message` object can be used to invoke the function
/// wrapped in `this` object.
///
/// \param Msg `rosa::Message` to check
///
/// \return whether `Msg` can be used to invoke the wrapped function
bool
match
(
const
Message
&
Msg
)
const
noexcept
override
{
return
Matcher
::
doesStronglyMatch
(
Msg
);
};
/// Tries to invoke the wrapped function with a `rosa::Message` object.
///
/// The wrapped function is invoked if the actual `rosa::Message` object can
/// be used to invoke it.
///
/// \param Msg `rosa::Message` to try to invoke the wrapped function with
///
/// \return whether the wrapped function could be invoked with `Msg`
result_t
operator
()(
const
Message
&
Msg
)
const
noexcept
override
{
if
(
match
(
Msg
))
{
LOG_TRACE
(
"Invoking with matching arguments"
);
invokeFunction
(
typename
GenSeq
<
sizeof
...(
Ts
)
+
1
>::
Type
(),
Matcher
::
extractedValues
(
Msg
));
return
result_t
::
Invoked
;
}
else
{
LOG_TRACE
(
"Tried to invoke with non-matching arguments"
);
return
result_t
::
NoMatch
;
}
}
};
template
<
typename
T
,
typename
...
Ts
>
template
<
size_t
...
S
>
void
InvokerImpl
<
std
::
function
<
void
(
T
,
Ts
...)
noexcept
>>::
invokeFunction
(
Seq
<
S
...
>
,
const
args_t
&
Args
)
const
noexcept
{
ASSERT
(
sizeof
...(
S
)
==
std
::
tuple_size
<
args_t
>::
value
);
// Sanity check.
F
(
std
::
get
<
S
>
(
Args
)...);
}
///@}
}
// End namespace
template
<
typename
T
,
typename
...
Ts
>
Invoker
::
invoker_t
Invoker
::
wrap
(
std
::
function
<
void
(
T
,
Ts
...)
noexcept
>
&&
F
)
noexcept
{
return
std
::
unique_ptr
<
Invoker
>
(
new
InvokerImpl
<
std
::
function
<
void
(
T
,
Ts
...)
noexcept
>>
(
std
::
move
(
F
)));
}
template
<
typename
C
,
typename
...
Ts
>
Invoker
::
F
<
Ts
...
>
Invoker
::
M
(
C
*
O
,
void
(
C
::*
Fun
)(
Ts
...)
noexcept
)
noexcept
{
return
[
O
,
Fun
](
Ts
...
Vs
)
noexcept
->
void
{
(
O
->*
Fun
)(
Vs
...);
};
}
}
// End namespace rosa
#endif
// ROSA_CORE_INVOKER_HPP
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Sun, May 31, 4:53 PM (1 d, 16 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
328238
Default Alt Text
Invoker.hpp (8 KB)
Attached To
Mode
R20 SoC_Rosa_repo
Attached
Detach File
Event Timeline
Log In to Comment