diff --git a/include/rosa/core/Message.hpp b/include/rosa/core/Message.hpp index 7448d80..35613fd 100644 --- a/include/rosa/core/Message.hpp +++ b/include/rosa/core/Message.hpp @@ -1,304 +1,304 @@ /******************************************************************************* * * 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" #include "rosa/core/forward_declarations.h" #include #include 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(const Type &, const Ts &...) noexcept; // No copy and move. Message(const Message &) = delete; Message(Message &&) = delete; Message &operator=(const Message &) = delete; Message &operator=(Message &&) = delete; public: // Factory function to locally create a Message instance from constant // lvalue references. template static message_t create(const Type &T, const Types &... Ts) noexcept; // Factory function to locally create a Message instance from rvalue // references. template static message_t create(Type &&T, Types &&... Ts) noexcept; // 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, that is the number of values stored in // Message. const size_t Size; // Virtual dtor. virtual ~Message(void); // Tells if the value in position Pos is of type Type. // NOTE: Token encodes atoms as AtomValue and not directly AtomConstants. // 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) template const Type &valueAt(const size_t Pos) const noexcept; protected: // Provides an untyped pointer for the value in position Pos. // PRE: Pos < Size virtual const void *pointerTo(const size_t Pos) const noexcept = 0; }; // Nested namespace with an implementation for Message, consider it private. namespace { // Template class for an implementation of Message, definition below. template class LocalMessage; // Initializes Arena with values from const lvalue references of Types. // NOTE: Arena needs to be a valid pointer to a memory area big enough for // values of Types. template inline void createMessageElements(void *const Arena, const Types &... Ts) noexcept; // NOTE: This terminal case is used for both constant lvalue references and // value references. template inline void createMessageElement(void *const, const std::vector &Offsets) { ASSERT(Pos == Offsets.size()); } -template -inline void -createMessageElement(void *const Arena, const std::vector &Offsets, - const AtomConstant &, const Types &... Ts) noexcept { - ASSERT(Arena != nullptr && Pos < Offsets.size()); - *static_cast( - static_cast(static_cast(Arena) + Offsets[Pos])) = V; - createMessageElement(Arena, Offsets, Ts...); -} - template inline void createMessageElement(void *const Arena, const std::vector &Offsets, const Type &T, const Types &... Ts) noexcept { ASSERT(Arena != nullptr && Pos < Offsets.size()); new (static_cast(static_cast(static_cast(Arena) + Offsets[Pos]))) Type(T); createMessageElement(Arena, Offsets, Ts...); } +template +inline void +createMessageElement(void *const Arena, const std::vector &Offsets, + const AtomConstant &, const Types &... Ts) noexcept { + ASSERT(Arena != nullptr && Pos < Offsets.size()); + *static_cast( + static_cast(static_cast(Arena) + Offsets[Pos])) = V; + createMessageElement(Arena, Offsets, Ts...); +} + template inline void createMessageElements(void *const Arena, const Type &T, const Types &... Ts) noexcept { ASSERT(Arena != nullptr); createMessageElement<0>(Arena, LocalMessage::Offsets, T, Ts...); } // Initializes Arena with values from rvalue references of Types. // NOTE: Arena needs to be a valid pointer to a memory area big enough for // values of Types. template inline void createMessageElements(void *const Arena, Types &&... Ts) noexcept; -template -inline void createMessageElement(void *const Arena, - const std::vector &Offsets, - AtomConstant &&, Types &&... Ts) noexcept { - ASSERT(Arena != nullptr && Pos < Offsets.size()); - *static_cast( - static_cast(static_cast(Arena) + Offsets[Pos])) = V; - createMessageElement(Arena, Offsets, std::move(Ts)...); -} - template inline void createMessageElement(void *const Arena, const std::vector &Offsets, Type &&T, Types &&... Ts) noexcept { ASSERT(Arena != nullptr && Pos < Offsets.size()); new (static_cast(static_cast( static_cast(Arena) + Offsets[Pos]))) Type(std::move(T)); createMessageElement(Arena, Offsets, std::move(Ts)...); } +template +inline void createMessageElement(void *const Arena, + const std::vector &Offsets, + AtomConstant &&, Types &&... Ts) noexcept { + ASSERT(Arena != nullptr && Pos < Offsets.size()); + *static_cast( + static_cast(static_cast(Arena) + Offsets[Pos])) = V; + createMessageElement(Arena, Offsets, std::move(Ts)...); +} + template inline void createMessageElements(void *const Arena, Type &&T, Types &&... Ts) noexcept { ASSERT(Arena != nullptr); createMessageElement<0>(Arena, LocalMessage::Offsets, std::move(T), std::move(Ts)...); } // Destroyes values of Types stored in Arena. // NOTE: Arena needs to be a valid pointer to a memory area where values of // Types are stored. template inline void destroyMessageElements(void *const Arena) noexcept; template inline void destroyMessageElement(void *const, const std::vector &Offsets) noexcept { ASSERT(Pos == Offsets.size()); } template inline void destroyMessageElement(void *const Arena, const std::vector &Offsets) noexcept { ASSERT(Arena != nullptr && Pos < Offsets.size()); static_cast( static_cast(static_cast(Arena) + Offsets[Pos])) ->~Type(); destroyMessageElement(Arena, Offsets); } template inline void destroyMessageElements(void *const Arena) noexcept { destroyMessageElement<0, Type, Types...>( Arena, LocalMessage::Offsets); } // Implementation of the template LocalMessage. Provides facilities for storing // values as a Message. template class LocalMessage : public Message { public: // Type Token for the stored values. // NOTE: Only for compile-time checks, static member is not defined. static constexpr Token ST = TypeToken::type, typename std::decay::type...>::Value; // Offsets required to access values in Arena. static const std::vector Offsets; private: // A BLOB storing all the values one after the other. void *const Arena; // Generates offset for accessing values in Arena. static std::vector offsets(void) noexcept { Token T = ST; // Need a mutable copy. size_t I = 0; // Start indexing from position 0. std::vector O(lengthOfToken(T)); // Allocate vector of proper size. O[0] = 0; // First offset is always 0. while (!emptyToken(T)) { ASSERT(I < O.size()); // Calculate next offset based on the previous one. O[I + 1] = O[I] + sizeOfHeadOfToken(T); dropHeadOfToken(T), ++I; } ASSERT(I == O.size()); return O; } public: // Ctor for constant lvalue references. LocalMessage(const Type &T, const Types &... Ts) noexcept : Message(T, Ts...), Arena(::operator new(sizeOfValuesOfToken(ST))) { ASSERT(this->T == ST && Size == Offsets.size() && Arena != nullptr); // Sanity check. createMessageElements(Arena, T, Ts...); } // Ctor for rvalue referecens. LocalMessage(Type &&T, Types &&... Ts) noexcept : Message(T, Ts...), Arena(::operator new(sizeOfValuesOfToken(ST))) { ASSERT(this->T == ST && Size == Offsets.size() && Arena != nullptr); // Sanity check. createMessageElements(Arena, std::move(T), std::move(Ts)...); } // Dtor. ~LocalMessage(void) { destroyMessageElements(Arena); ::operator delete(Arena); } // Provides an untyped pointer for the constant value at Pos. const void *pointerTo(const size_t Pos) const noexcept override { ASSERT(Pos < Offsets.size()); return static_cast(Arena) + Offsets[Pos]; } }; // Implementation of the static member field Offsets. template const std::vector LocalMessage::Offsets = LocalMessage::offsets(); } // End namespace template Message::Message(const Type &, const Ts &...) noexcept : T(TypeToken::type, typename std::decay::type...>::Value), Size(lengthOfToken(T)) { ASSERT(validToken(T) && lengthOfToken(T) == (1 + sizeof...(Ts))); // Sanity check. LOG_TRACE("Creating Message with Token(" + to_string(T) + ")"); } template message_t Message::create(const Type &T, const Types &... Ts) noexcept { return message_t(new LocalMessage(T, Ts...)); } template message_t Message::create(Type &&T, Types &&... Ts) noexcept { return message_t( new LocalMessage(std::move(T), std::move(Ts)...)); } template bool Message::isTypeAt(const size_t Pos) const noexcept { ASSERT(Pos < Size); Token T_ = T; // NOLINT dropNOfToken(T_, Pos); return isHeadOfTokenTheSameType(T_); } template const Type &Message::valueAt(const size_t Pos) const noexcept { ASSERT(Pos < Size && isTypeAt(Pos)); return *static_cast(pointerTo(Pos)); } } // End namespace rosa #endif // ROSA_CORE_MESSAGE_HPP