diff --git a/examples/messaging/messaging.cpp b/examples/messaging/messaging.cpp index 693bf76..7c99255 100644 --- a/examples/messaging/messaging.cpp +++ b/examples/messaging/messaging.cpp @@ -1,139 +1,139 @@ /******************************************************************************* * * 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 + << " 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 + << " 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 { 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/Message.hpp b/include/rosa/core/Message.hpp index ed03649..74d124a 100644 --- a/include/rosa/core/Message.hpp +++ b/include/rosa/core/Message.hpp @@ -1,97 +1,92 @@ /******************************************************************************* * * File: Message.hpp * * Contents: Declaration of Message base-class. * * Copyright 2017 * * Author: David Juhasz (david.juhasz@tuwien.ac.at) * ******************************************************************************/ #ifndef ROSA_CORE_MESSAGE_HPP #define ROSA_CORE_MESSAGE_HPP #include "rosa/support/log.h" #include "rosa/support/type_token.hpp" namespace rosa { // Message interface. The interface provides means to check the type of the // stored values, but actual data is to be managed by derived implementations. // Messages are immutable data objects, obtaining their data upon creation and // providing only constant references for the stored values. // NOTE: Any reference obtained from a Message instance remains valid only as // long as the owning Message object is not destroyed. class Message { protected: // Ctor. // NOTE: No implementation for empty list. template Message(Type, Ts...) noexcept; -private: // No copy and move. Message(const Message &) = delete; Message(Message &&) = delete; Message &operator=(const Message &) = delete; Message &operator=(Message &&) = delete; +public: // A valid, non-empty token representing the types of the values stored in // the Message. const Token T; - // The number of types encoded in T. - const size_t N; + // The number of types encoded in T, that is the number of values stored in + // Message. + const size_t Size; -public: // Virtual dtor. virtual ~Message(void); - // Tells how many values are in the message. - inline size_t size(void) const noexcept; - // Tells if the value in position Pos is of type Type. // NOTE: Token encodes atoms as AtomValue and not directly AtomConstants. - // PRE: Pos < size() + // PRE: Pos < Size template bool isTypeAt(const size_t Pos) const noexcept; // Gives a constant reference of the value of type Type in position Pos. - // PRE: Pos < size() && isTypeAt(Pos) + // PRE: Pos < Size && isTypeAt(Pos) template const Type &getValueAt(const size_t Pos) const noexcept; protected: // Provides an untyped pointer for the value in position Pos. - // PRE: Pos < size() + // PRE: Pos < Size virtual const void *getPointerTo(const size_t Pos) const noexcept = 0; }; template Message::Message(Type, Ts...) noexcept : T(TypeToken::Value), - N(lengthOfToken(T)) { - ASSERT(!emptyToken(T) && validToken(T) && + Size(lengthOfToken(T)) { + ASSERT(validToken(T) && lengthOfToken(T) == (1 + sizeof...(Ts))); // Sanity check. LOG_TRACE("Creating Message with Token(" + to_string(T) + ")"); } -size_t Message::size(void) const noexcept { return N; } - template bool Message::isTypeAt(const size_t Pos) const noexcept { - ASSERT(Pos < size()); + ASSERT(Pos < Size); Token T_ = T; // NOLINT dropNOfToken(T_, Pos); return isHeadOfTokenTheSameType(T_); } template const Type &Message::getValueAt(const size_t Pos) const noexcept { - ASSERT(Pos < size() && isTypeAt(Pos)); + ASSERT(Pos < Size && isTypeAt(Pos)); return *static_cast(getPointerTo(Pos)); } } // End namespace rosa #endif // ROSA_CORE_MESSAGE_HPP diff --git a/include/rosa/core/MessageMatcher.hpp b/include/rosa/core/MessageMatcher.hpp index f7d5466..5056a8d 100644 --- a/include/rosa/core/MessageMatcher.hpp +++ b/include/rosa/core/MessageMatcher.hpp @@ -1,159 +1,164 @@ /******************************************************************************* * * File: MessageMatcher.hpp * * Contents: Implementation of MessageMatcher. * * Copyright 2017 * * Author: David Juhasz (david.juhasz@tuwien.ac.at) * ******************************************************************************/ #ifndef ROSA_CORE_MESSAGEMATCHER_HPP #define ROSA_CORE_MESSAGEMATCHER_HPP #include "rosa/core/Message.hpp" #include namespace rosa { // Template class with static functions type-checking a Message instance and // extracting stored values from Message instsances into std::tuple instances // with matching type arguments. template struct MessageMatcher; // Definition of MessageMatcher for non-empty lists of types, like Message // itself. -template -struct MessageMatcher> { +template +struct MessageMatcher> { + + // Type Token associated with the give TypeList. + static constexpr Token T = TypeToken::Value; + // Tells if stored values in Msg are matching types given as // TypeList, considering exact AtomConstants instead of AtomValues. static inline bool doesStronglyMatch(const Message &Msg) noexcept; // Gives a std::tuple with references to values stored in a type-matching Msg. // PRE: doesStronglyMatch(Msg) - static inline std::tuple + static inline std::tuple extractedValues(const Message &Msg) noexcept; }; // Convenience template alias turning a list of types into a TypeList for // MessageMatcher. -template -using MsgMatcher = MessageMatcher>; +template +using MsgMatcher = MessageMatcher>; // Nested namespace with implementation for features of MessageMatcher, // consider it private. namespace { // Helper struct implementing type-checking and value extraction for // MessageMatcher. template struct MessageMatcherImpl; // Specialization handling the empty list of types. template <> struct MessageMatcherImpl { static inline bool doesStronglyMatchFrom(const Message &Msg, const size_t Pos) noexcept { // Matching EmptyTypeList only if reached the end of the stored types. - return Pos == Msg.size(); + return Pos == Msg.Size; } static inline std::tuple<> extractedValuesFrom(const Message &Msg, const size_t Pos) noexcept { // It is valid to extract an empty list only if we reached the end of // stored values. ASSERT(doesStronglyMatchFrom(Msg, Pos)); return std::tie(); } }; // Specialization handling an AtomValue in the head. template struct MessageMatcherImpl, Ts...>> { static inline bool doesHeadStronglyMatchAt(const Message &Msg, const size_t Pos) noexcept { // Matching an AtomConstant in the head if there is a type stored at Pos, // the stored type is AtomValue, and the corresponding value matches the // AtomValue V. - return Pos < Msg.size() && Msg.isTypeAt(Pos) && + return Pos < Msg.Size && Msg.isTypeAt(Pos) && Msg.getValueAt(Pos) == V; } static inline bool doesStronglyMatchFrom(const Message &Msg, const size_t Pos) noexcept { // Matching a non-empty list if the head is matching and the rest of the // list is matching. return doesHeadStronglyMatchAt(Msg, Pos) && MessageMatcherImpl>::doesStronglyMatchFrom(Msg, Pos + 1); } static inline std::tuple &, const Ts &...> extractedValuesFrom(const Message &Msg, const size_t Pos) noexcept { // Extracting for a non-empty list with a matching AtomConstant in the head // by getting the encoded AtomConstant and concatenating it with values // extracted for the rest of the list. ASSERT(doesHeadStronglyMatchAt(Msg, Pos)); return std::tuple_cat( std::tie(AtomConstant::Value), MessageMatcherImpl>::extractedValuesFrom(Msg, Pos + 1)); } }; // Specialization handling an regular builtin type (not an AtomConstant) in the // head. template struct MessageMatcherImpl> { static inline bool doesHeadStronglyMatchAt(const Message &Msg, const size_t Pos) noexcept { // Matching the head if there is a type stored at Pos, and the stored type // is T. - return Pos < Msg.size() && Msg.isTypeAt(Pos); + return Pos < Msg.Size && Msg.isTypeAt(Pos); } static inline bool doesStronglyMatchFrom(const Message &Msg, const size_t Pos) noexcept { // Matching a non-empty list if the head is matching and the rest of the // list is matching. return doesHeadStronglyMatchAt(Msg, Pos) && MessageMatcherImpl>::doesStronglyMatchFrom(Msg, Pos + 1); } static inline std::tuple extractedValuesFrom(const Message &Msg, const size_t Pos) noexcept { // Extracting for a non-empty list with a matching head by getting the // value for the head and concatenating it with values extracted for the // rest of the list. ASSERT(doesHeadStronglyMatchAt(Msg, Pos)); return std::tuple_cat( std::tie(Msg.getValueAt(Pos)), MessageMatcherImpl>::extractedValuesFrom(Msg, Pos + 1)); } }; } // End namespace -template -bool MessageMatcher>::doesStronglyMatch( +template +bool MessageMatcher>::doesStronglyMatch( const Message &Msg) noexcept { - // NOTE: Fail quick on the size. - return (1 + sizeof...(Ts)) == Msg.size() && - MessageMatcherImpl>::doesStronglyMatchFrom(Msg, 0); + // NOTE: Fail quick on the size and T. + return (1 + sizeof...(Ts)) == Msg.Size && T == Msg.T && + MessageMatcherImpl>::doesStronglyMatchFrom(Msg, + 0); } -template -std::tuple -MessageMatcher>::extractedValues( +template +std::tuple +MessageMatcher>::extractedValues( const Message &Msg) noexcept { ASSERT(doesStronglyMatch(Msg)); - return MessageMatcherImpl>::extractedValuesFrom(Msg, 0); + return MessageMatcherImpl>::extractedValuesFrom(Msg, 0); } } // End namespace rosa #endif // ROSA_CORE_MESSAGEMATCHER_HPP