Page MenuHomePhorge

Message.hpp
No OneTemporary

Size
17 KB
Referenced Files
None
Subscribers
None

Message.hpp

//===-- rosa/core/Message.hpp -----------------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/core/Message.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017
///
/// \brief Declaration of \c rosa::Message base-class.
///
//===----------------------------------------------------------------------===//
#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 <memory>
#include <vector>
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.
///
/// A \c rosa::Message instance is an immutable data object that obtains its
/// data upon creation and provides only constant references for the stored
/// values.
///
/// \note Any reference obtained from a \c rosa::Message instance remains valid
/// only as long as the owning \c rosa::Message object is not destroyed.
class Message {
protected:
/// Creates a new instance.
///
/// \note No implementation for empty list.
///
/// \tparam Type type of the mandatory first argument
/// \tparam Types types of any further arguments
///
/// \note the actual arguments are ignored by the constructor it is only
/// their type that matters. The actual values are supposed to be handled by
/// any implementation derived from \c rosa::Message.
///
/// \pre \p Type and \p Types are all built-in types and the number of stored
/// values does not exceed \c rosa::token::MaxTokenizableListSize.
template <typename Type, typename... Types>
Message(const Type &, const Types &...) noexcept;
/// No copying and moving of \c rosa::Message instances.
///@{
Message(const Message &) = delete;
Message(Message &&) = delete;
Message &operator=(const Message &) = delete;
Message &operator=(Message &&) = delete;
///@}
public:
/// Creates a \c rosa::message_t object from constant lvalue references.
///
/// \tparam Type type of the mandatory first argument
/// \tparam Types types of any further arguments
///
/// \param T the first value to include in the \c rosa::Message
/// \param Ts optional further values to include in the \c rosa::Message
///
/// \return new \c rosa::message_t object created from the given arguments
template <typename Type, typename... Types>
static message_t create(const Type &T, const Types &... Ts) noexcept;
/// Creates a \c rosa::message_t object from rvalue references.
///
/// \tparam Type type of the mandatory first argument
/// \tparam Types types of any further arguments
///
/// \param T the first value to include in the \c rosa::Message
/// \param Ts optional further values to include in the \c rosa::Message
///
/// \return new \c rosa::message_t object created from the given arguments
template <typename Type, typename... Types>
static message_t create(Type &&T, Types &&... Ts) noexcept;
/// Represents the types of the values stored in \p this object.
///
/// A valid, non-empty \c rosa::Token representing the types of the values
/// stored in \p this object.
const Token T;
/// The number of values stored in \p this object.
///
/// That is the number of types encoded in \c rosa::Message::T.
const size_t Size;
/// Destroys \p this object.
virtual ~Message(void);
/// Tells if the value stored at a given index is of a given type.
///
/// \note Any \c rosa::AtomConstant is encoded in \c rosa::Token as
/// the \c rosa::AtomValue wrapped into it.
///
/// \tparam Type type to match against
///
/// \param Pos index the type of the value at is to be matched against \p Type
///
/// \return if the value at index \p Pos of type \p Type
///
/// \pre \p Pos is a valid index:\code
/// Pos < Size
/// \endcode
template <typename Type> bool isTypeAt(const size_t Pos) const noexcept;
/// Gives a constant reference of a value of a given type stored at a given
/// index.
///
/// \tparam Type type to give a reference of
///
/// \param Pos index to set the reference for
///
/// \return constant reference of \p Type for the value stored at index \p Pos
///
/// \pre \p Pos is a valid index and the value at index \p Pos is of type
/// \p Type:\code
/// Pos < Size && isTypeAt(Pos)
/// \endcode
template <typename Type> const Type &valueAt(const size_t Pos) const noexcept;
protected:
/// Provides an untyped pointer for the value at a given index.
///
/// \param Pos index to take a pointer for
///
/// \return untyped pointer for the value stored at index \p Pos
///
/// \pre \p Pos is a valid index:\code
/// Pos < Size
/// \endcode
virtual const void *pointerTo(const size_t Pos) const noexcept = 0;
};
/// Nested namespace with implementation for \c rosa::Message, consider it
/// private.
namespace {
/// Template class for an implementation of \c rosa::Message.
///
/// \tparam Types types whose values are to be stored
template <typename... Types> class LocalMessage;
/// Initializes a pre-allocated memory area with values from constant lvalue
/// references.
///
/// \tparam Types types whose values are to be stored
///
/// \param Arena pre-allocated memory area to store values to
/// \param Ts the values to store in \p Arena
///
/// \note \p Arena needs to be a valid pointer to a memory area big enough for
/// values of \p Types.
template <typename... Types>
inline void createMessageElements(void *const Arena,
const Types &... Ts) noexcept;
/// \defgroup createMessageElement from const lvalue references
///
/// Stores values from constant lvalue references into a pre-allocated memory
/// area.
///
/// \note To be used by the implementation of \c createMessageElements.
///
/// \todo Document these functions.
///@{
/// \note This terminal case is used for both constant lvalue references and
/// value references.
template <size_t Pos>
inline void createMessageElement(void *const,
const std::vector<size_t> &Offsets) {
ASSERT(Pos == Offsets.size());
}
template <size_t Pos, typename Type, typename... Types>
inline void createMessageElement(void *const Arena,
const std::vector<size_t> &Offsets,
const Type &T, const Types &... Ts) noexcept {
ASSERT(Arena != nullptr && Pos < Offsets.size());
new (static_cast<Type *>(static_cast<void *>(static_cast<uint8_t *>(Arena) +
Offsets[Pos]))) Type(T);
createMessageElement<Pos + 1>(Arena, Offsets, Ts...);
}
template <size_t Pos, AtomValue V, typename... Types>
inline void
createMessageElement(void *const Arena, const std::vector<size_t> &Offsets,
const AtomConstant<V> &, const Types &... Ts) noexcept {
ASSERT(Arena != nullptr && Pos < Offsets.size());
*static_cast<AtomValue *>(
static_cast<void *>(static_cast<uint8_t *>(Arena) + Offsets[Pos])) = V;
createMessageElement<Pos + 1>(Arena, Offsets, Ts...);
}
///@}
/// Implementation of the template.
///
/// \tparam Type the type of the mandatory first value to store
/// \tparam Types types of any further values to store
///
/// \param Arena pre-allocated memory area to store values to
/// \param T the first value to store in \p Arena˛
/// \param Ts optional further values to store in \p Arena
///
/// \pre \p Arena is not \p nullptr.
template <typename Type, typename... Types>
inline void createMessageElements(void *const Arena, const Type &T,
const Types &... Ts) noexcept {
ASSERT(Arena != nullptr);
createMessageElement<0>(Arena, LocalMessage<Type, Types...>::Offsets, T,
Ts...);
}
/// Initializes a pre-allocated memory area with values from rvalue references.
///
/// \tparam Types types whose values are to be stored
///
/// \param Arena pre-allocated memory area to store values to
/// \param Ts the values to store in \p Arena
///
/// \note \p Arena needs to be a valid pointer to a memory area big enough for
/// values of \p Types.
template <typename... Types>
inline void createMessageElements(void *const Arena, Types &&... Ts) noexcept;
/// \defgroup createMessageElement from rvalue references
///
/// Stores values from rvalue references into a pre-allocated memory area.
///
/// \note To be used by the implementation of \c createMessageElements.
///
/// \todo Document these functions.
///@{
template <size_t Pos, typename Type, typename... Types>
inline void createMessageElement(void *const Arena,
const std::vector<size_t> &Offsets, Type &&T,
Types &&... Ts) noexcept {
ASSERT(Arena != nullptr && Pos < Offsets.size());
new (static_cast<Type *>(static_cast<void *>(
static_cast<uint8_t *>(Arena) + Offsets[Pos]))) Type(std::move(T));
createMessageElement<Pos + 1>(Arena, Offsets, std::move(Ts)...);
}
template <size_t Pos, AtomValue V, typename... Types>
inline void createMessageElement(void *const Arena,
const std::vector<size_t> &Offsets,
AtomConstant<V> &&, Types &&... Ts) noexcept {
ASSERT(Arena != nullptr && Pos < Offsets.size());
*static_cast<AtomValue *>(
static_cast<void *>(static_cast<uint8_t *>(Arena) + Offsets[Pos])) = V;
createMessageElement<Pos + 1>(Arena, Offsets, std::move(Ts)...);
}
///@}
/// Implementation of the template.
///
/// \tparam Type the type of the mandatory first value to store
/// \tparam Types types of any further values to store
///
/// \param Arena pre-allocated memory area to store values to
/// \param T the first value to store in \p Arena
/// \param Ts optional further values to store in \p Arena
///
/// \pre \p Arena is not \c nullptr.
template <typename Type, typename... Types>
inline void createMessageElements(void *const Arena, Type &&T,
Types &&... Ts) noexcept {
ASSERT(Arena != nullptr);
createMessageElement<0>(Arena, LocalMessage<Type, Types...>::Offsets,
std::move(T), std::move(Ts)...);
}
/// Destroys values allocated by \c createMessageElements.
///
/// \tparam Type type of the mandatory first value stored in \p Arena
/// \tparam Types futher types whose values are stored in \p Arena
///
/// \param Arena the memory area to destroy values from
///
/// \note \p Arena needs to be a valid pointer to a memory area where values of
/// \p Types are stored.
template <typename Type, typename... Types>
inline void destroyMessageElements(void *const Arena) noexcept;
/// \defgroup destroyMessageElement
///
/// Destroys values from a memory area.
///
/// \note To be used by the implementation of \c destroyMessageElements.
///
/// \todo Document these functions.
///@{
template <size_t Pos>
inline void destroyMessageElement(void *const,
const std::vector<size_t> &Offsets) noexcept {
ASSERT(Pos == Offsets.size());
}
template <size_t Pos, typename Type, typename... Types>
inline void destroyMessageElement(void *const Arena,
const std::vector<size_t> &Offsets) noexcept {
ASSERT(Arena != nullptr && Pos < Offsets.size());
static_cast<Type *>(
static_cast<void *>(static_cast<uint8_t *>(Arena) + Offsets[Pos]))
->~Type();
destroyMessageElement<Pos + 1, Types...>(Arena, Offsets);
}
///@}
/// Implementation of the template.
///
/// \tparam Type the type of the mandatory first value to destroy
/// \tparam Types types of any further values to destroy
///
/// \param Arena the memory area to destroy values from
///
/// \pre \p Arena is not \c nullptr.
template <typename Type, typename... Types>
inline void destroyMessageElements(void *const Arena) noexcept {
ASSERT(Arena != nullptr);
destroyMessageElement<0, Type, Types...>(
Arena, LocalMessage<Type, Types...>::Offsets);
}
/// Implementation of the template \c rosa::LocalMessage providing facilities
/// for storing values as a \c rosa::Message object.
///
/// \tparam Type type of the first mandatory value of the \c rosa::Message
/// \tparam Types of any further values
template <typename Type, typename... Types>
class LocalMessage<Type, Types...> : public Message {
public:
/// \c rosa::Token for the stored values.
///
/// \note Only for compile-time checks! This static member is not defined
/// because it must be the same as \c rosa::Message::T.
static constexpr Token ST =
TypeToken<typename std::decay<Type>::type,
typename std::decay<Types>::type...>::Value;
/// Byte offsets to access stored values in \c LocalMessage::Arena.
static const std::vector<size_t> Offsets;
private:
/// A BLOB storing all the values one after the other.
void *const Arena;
/// Generates byte offsets for accessing values stored in
/// \c LocalMessage::Arena.
///
/// \return \c std::vector containing byte offsets for accessing values stored
/// in \c LocalMessage::Arena
static std::vector<size_t> offsets(void) noexcept {
Token T = ST; // Need a mutable copy.
const size_t N = lengthOfToken(T); // Number of types encoded in \c T.
size_t I = 0; // Start indexing from position \c 0.
std::vector<size_t> O(N); // Allocate vector of proper size.
O[0] = 0; // First offset is always \c 0.
while (I < N - 1) {
ASSERT(I + 1 < O.size() && lengthOfToken(T) == N - I);
// Calculate next offset based on the previous one.
// \note The offset of the last value is stored at `O[N - 1]`, which is
// set when `I == N - 2`. Hence the limit of the loop.
O[I + 1] = O[I] + sizeOfHeadOfToken(T);
dropHeadOfToken(T), ++I;
}
ASSERT(I + 1 == O.size() && lengthOfToken(T) == 1);
return O;
}
public:
/// Creates an instance from constant lvalue references.
///
/// \param T the mandatory first value to store in the \c rosa::Message object
/// \param Ts optional further values to store in the \c rosa::Message object
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...);
}
/// Creates an instance from rvalue references.
///
/// \param T the mandatory first value to store in the \c rosa::Message object
/// \param Ts optional further values to store in the \c rosa::Message object
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)...);
}
// Destroys \p this object.
~LocalMessage(void) {
destroyMessageElements<Type, Types...>(Arena);
::operator delete(Arena);
}
/// Provides an untyped pointer for the constant value stored at a position.
///
/// \param Pos the index of the value to return an untyped pointer for
///
/// \return untyped pointer for the constant value stored at index \p Pos
const void *pointerTo(const size_t Pos) const noexcept override {
ASSERT(Pos < Offsets.size());
return static_cast<uint8_t *>(Arena) + Offsets[Pos];
}
};
// Implementation of the static member field \c LocalMessage::Offsets.
template <typename Type, typename... Types>
const std::vector<size_t> LocalMessage<Type, Types...>::Offsets =
LocalMessage<Type, Types...>::offsets();
} // End namespace
template <typename Type, typename... Types>
Message::Message(const Type &, const Types &...) noexcept
: T(TypeToken<typename std::decay<Type>::type,
typename std::decay<Types>::type...>::Value),
Size(lengthOfToken(T)) {
ASSERT(validToken(T) &&
lengthOfToken(T) == (1 + sizeof...(Types))); // Sanity check.
LOG_TRACE("Creating Message with Token(" + to_string(T) + ")");
}
/// \note The implementation instantiates a private local template class
/// \c LocalMessage.
template <typename Type, typename... Types>
message_t Message::create(const Type &T, const Types &... Ts) noexcept {
return message_t(new LocalMessage<Type, Types...>(T, Ts...));
}
/// \note The implementation instantiates a private local template class
/// \c LocalMessage.
template <typename Type, typename... Types>
message_t Message::create(Type &&T, Types &&... Ts) noexcept {
return message_t(
new LocalMessage<Type, Types...>(std::move(T), std::move(Ts)...));
}
template <typename Type>
bool Message::isTypeAt(const size_t Pos) const noexcept {
ASSERT(Pos < Size);
Token TT = T;
dropNOfToken(TT, Pos);
return isHeadOfTokenTheSameType<Type>(TT);
}
template <typename Type>
const Type &Message::valueAt(const size_t Pos) const noexcept {
ASSERT(Pos < Size && isTypeAt<Type>(Pos));
return *static_cast<const Type *>(pointerTo(Pos));
}
} // End namespace rosa
#endif // ROSA_CORE_MESSAGE_HPP

File Metadata

Mime Type
text/x-c++
Expires
Sun, May 31, 5:25 PM (15 h, 57 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
328262
Default Alt Text
Message.hpp (17 KB)

Event Timeline