diff --git a/examples/messaging/messaging.cpp b/examples/messaging/messaging.cpp index 7c99255..92cc1b3 100644 --- a/examples/messaging/messaging.cpp +++ b/examples/messaging/messaging.cpp @@ -1,139 +1,136 @@ /******************************************************************************* * * File: messaging.cpp * * Contents: An example showcasing features related to Messages. * * Copyright 2017 * * Author: David Juhasz (david.juhasz@tuwien.ac.at) * ******************************************************************************/ #include "rosa/config/version.h" #include "rosa/core/Invoker.hpp" #include "rosa/support/log.h" #include "rosa/support/terminal_colors.h" #include using namespace rosa; using namespace rosa::terminal; // A simple implementation of the Message interface with two hardcoded types. class MyMessage : public Message { const uint8_t U8; // First value const uint16_t U16; // Second value public: MyMessage(const uint8_t U8, const uint16_t U16) : Message(U8, U16), U8(U8), U16(U16) {} const void *getPointerTo(const size_t Pos) const noexcept override { switch (Pos) { default: ROSA_CRITICAL("wrong position"); case 0: return &U8; case 1: return &U16; } } }; class MyAtomMessage : public Message { const AtomValue A; // First value public: template MyAtomMessage(AtomConstant C) : Message(C), A(V) {} const void *getPointerTo(const size_t Pos) const noexcept override { switch (Pos) { default: ROSA_CRITICAL("wrong position"); case 0: return &A; } } }; int main(void) { LOG_INFO_STREAM << library_string() << " -- " << Color::Red << "messaging" << Color::Default << std::endl; auto &Log = LOG_TRACE_STREAM << std::endl; MyMessage Msg(1, 2); Log << "Checking on 'MyMessage(1, 2)' that is of 'Message with " "TypeList<>':" << std::endl << " Size: " << Msg.Size << std::endl << " Pos 0 is uint8_t: " << Msg.isTypeAt(0) << std::endl << " Pos 1 is uint16_t: " << Msg.isTypeAt(1) << std::endl << " Pos 2 is uint32_t: " << Msg.isTypeAt(1) << std::endl << " Value at pos 0: " << PRINTABLE(uint8_t)(Msg.getValueAt(0)) << std::endl << " Value at pos 1: " << Msg.getValueAt(1) << std::endl << std::endl; using MyMatcher = MsgMatcher; Log << "Matching against 'TypeList':" << std::endl << " matching: " << MyMatcher::doesStronglyMatch(Msg) << std::endl; auto Vs = MyMatcher::extractedValues(Msg); Log << " value: '(" << PRINTABLE(uint8_t)(std::get<0>(Vs)) << ", " << std::get<1>(Vs) << ")'" << std::endl << std::endl; using MyWrongMatcher = MsgMatcher; Log << "Matching against 'TypeList':" << std::endl << " matching: " << MyWrongMatcher::doesStronglyMatch(Msg) << std::endl << std::endl; using MyAtom = AtomConstant; const MyAtom &A = MyAtom::Value; using MyNAtom = AtomConstant; MyAtomMessage AMsg(A); Log << "Checking on 'MyAtomMessage(AtomConstant::Value)' " "that is of 'Message with TypeList>':" << std::endl << " Size: " << AMsg.Size << std::endl << " Pos 0 is 'AtomValue': " << AMsg.isTypeAt(0) << std::endl << " Pos 0 is 'AtomConstant': " << AMsg.isTypeAt(0) << std::endl << std::endl; using MyAtomMatcher = MsgMatcher; Log << "Matching against 'TypeList>':" << std::endl << " matching: " << MyAtomMatcher::doesStronglyMatch(AMsg) << std::endl << " value: '(" << to_string(std::get<0>(MyAtomMatcher::extractedValues(AMsg))) << ")'" << std::endl << std::endl; using MyWrongAtomMatcher = MsgMatcher; Log << "Matching against 'TypeList>':" << std::endl << " matching: " << MyWrongAtomMatcher::doesStronglyMatch(AMsg) << std::endl << std::endl; - // FIXME: Is this a compiler bug, - // cannot use Invoker::wrap([&](MyAtom)... ??? - auto WrapFix = Invoker::wrap; - auto IP = WrapFix([&Log](MyAtom) noexcept->void { + auto IP = Invoker::wrap(Invoker::F([&Log](MyAtom) noexcept->void { Log << "** Lambda-function called via Invoker." << std::endl; - }); + })); auto &I = *IP; // Get a reference from the pointer. Log << "Invoking a function of signature 'void(MyAtom) noexcept':" << std::endl << " with 'Message with TypeList'" << std::endl << " does Message match Invoker: " << I.match(Msg) << std::endl << " invoking..." << std::endl; I(Msg); Log << " with 'Message with TypeList'..." << std::endl << " does Message match Invoker: " << I.match(AMsg) << std::endl << " invoking..." << std::endl; I(AMsg); return 0; } diff --git a/include/rosa/core/Invoker.hpp b/include/rosa/core/Invoker.hpp index 136e998..82ba840 100644 --- a/include/rosa/core/Invoker.hpp +++ b/include/rosa/core/Invoker.hpp @@ -1,150 +1,156 @@ /******************************************************************************* * * 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 #include 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; + // 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 - static std::unique_ptr - wrap(std::function &&F) noexcept; + static invoker_t wrap(std::function &&F) noexcept; + + // Convenience template alias for casting callable stuff to function objects + // for wrapping. + template using F = std::function; }; // 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 class InvokerImpl; // Empty struct just to store a sequence of numbers in compile time as template // arguments. template struct Seq {}; // Sequence generator, the general case when counting down by extending the // sequence. template struct GenSeq : GenSeq {}; // Sequence generator, the terminal case when storing the generated sequence // into Seq. template struct GenSeq<0, S...> { using Type = Seq; }; // Specialization of InvokerImpl template for std::function. // NOTE: No std::function. template class InvokerImpl> final : public Invoker { // Type alias for the stored function. using function_t = std::function; // Type alias for correctly typed argument-tuples as obtained from Messages. using args_t = std::tuple; // Alias for MessageMatcher for the arguments of the stored function. using Matcher = MsgMatcher; // 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::value template inline void invokeFunction(Seq, 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::Type(), Matcher::extractedValues(Msg)); return result_t::Invoked; } else { LOG_TRACE("Tried to invoke with non-matching arguments"); return result_t::NoMatch; } } }; template template void InvokerImpl>::invokeFunction( Seq, const args_t &Args) const noexcept { ASSERT(sizeof...(S) == std::tuple_size::value); // Sanity check. F(std::get(Args)...); } } // End namespace template -std::unique_ptr +Invoker::invoker_t Invoker::wrap(std::function &&F) noexcept { return std::unique_ptr( new InvokerImpl>(std::move(F))); } } // End namespace rosa #endif // ROSA_CORE_INVOKER_HPP