Page MenuHomePhorge

Invoker.hpp
No OneTemporary

Size
4 KB
Referenced Files
None
Subscribers
None

Invoker.hpp

/*******************************************************************************
*
* File: Invoker.hpp
*
* Contents: Definition of Invoker interface and its implementation.
*
* Copyright 2017
*
* Author: David Juhasz (david.juhasz@tuwien.ac.at)
*
******************************************************************************/
#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 Message.
// NOTE: Invoker instances are supposed to be owned by Message handlers, and
// not being used directly from user code.
class Invoker {
protected:
// Protected ctor, only subclasses can instantiate.
Invoker(void) noexcept;
public:
// Dtor.
virtual ~Invoker(void);
// Enumeration of possible results of an invocation.
enum class Result { NoMatch, Invoked };
// Type alias for a smart-pointer for Invoker.
using invoker_t = std::unique_ptr<const Invoker>;
// Type alias for Result.
using result_t = Result;
// Tells if Msg can be used to invoke F.
virtual bool match(const Message &Msg) const noexcept = 0;
// Invokes F with Msg if Msg can be used to invoke F.
virtual result_t operator()(const Message &Msg) const noexcept = 0;
// Instantiates an implementation of Invoker with the given function.
// NOTE: As there is no empty Message, no Invoker wraps a function without an
// argument.
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.
// FIXME: 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>;
};
// Nested namespace with Invoker implementation and helper templates, consider
// it private.
namespace {
// Implementation of the Invoker interface, for functions with different
// signature.
// NOTE: As there is no empty Message, no Invoker wraps a function without an
// argument.
template <typename Fun> class InvokerImpl;
// Empty struct just 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 Seq.
template <size_t... S> struct GenSeq<0, S...> { using Type = Seq<S...>; };
// Specialization of InvokerImpl template for std::function.
// NOTE: 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 Messages.
using args_t = std::tuple<const T &, const Ts &...>;
// Alias for MessageMatcher for the arguments of the stored function.
using Matcher = MsgMatcher<T, Ts...>;
// The wrapped function.
const function_t F;
// Helper function invoking F by unpacking Args with the help of actual
// template arguments.
// PRE: sizeof...(S) == std::tuple_size<args_t>::value
template <size_t... S>
inline void invokeFunction(Seq<S...>, const args_t &Args) const noexcept;
public:
// Ctor.
InvokerImpl(function_t &&F) noexcept : F(F) {
ASSERT(bool(F)); // Sanity check.
}
// Dtor.
~InvokerImpl(void) = default;
// Tells if Msg can be used to invoke F.
bool match(const Message &Msg) const noexcept override {
return Matcher::doesStronglyMatch(Msg);
};
// Invokes F with Msg if Msg can be used to invoke F.
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)));
}
} // End namespace rosa
#endif // ROSA_CORE_INVOKER_HPP

File Metadata

Mime Type
text/x-c++
Expires
Sun, Apr 12, 11:38 AM (1 d, 11 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
300834
Default Alt Text
Invoker.hpp (4 KB)

Event Timeline