Page MenuHomePhorge

Message.hpp
No OneTemporary

Size
10 KB
Referenced Files
None
Subscribers
None

Message.hpp

/*******************************************************************************
*
* 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 <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.
// 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 <typename Type, typename... Ts>
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:
// Type alias for a smart pointer for Message.
using message_t = std::unique_ptr<Message>;
// Factory function to locally create a Message instance from constant
// references.
template <typename Type, typename... Types>
static message_t create(const Type &T, const Types &... Ts) noexcept;
// Factory function to locally create a Message instance from movable
// references.
template <typename Type, typename... Types>
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 <typename Type> 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 <typename Type>
const Type &getValueAt(const size_t Pos) const noexcept;
protected:
// Provides an untyped pointer for the value in position Pos.
// PRE: Pos < Size
virtual const void *getPointerTo(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 <typename... Types> class LocalMessage;
// Initializes Arena with values from const references of Types.
// NOTE: Arena needs to be a valid pointer to a memory area big enough for
// values of Types.
template <typename... Types>
inline void createMessageElements(void *const Arena,
const Types &... Ts) noexcept;
// NOTE: This terminal case is used for both constant references and movable
// references.
template <size_t Pos>
inline void createMessageElement(void *const,
const std::vector<size_t> &Offsets) {
ASSERT(Pos == Offsets.size());
}
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...);
}
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 <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 Arena with values from movable references of Types.
// NOTE: Arena needs to be a valid pointer to a memory area big enough for
// values of Types.
template <typename... Types>
inline void createMessageElements(void *const Arena, Types &&... Ts) noexcept;
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)...);
}
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 <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)...);
}
// 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 <typename Type, typename... Types>
inline void destroyMessageElements(void *const Arena) noexcept;
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);
}
template <typename Type, typename... Types>
inline void destroyMessageElements(void *const Arena) noexcept {
destroyMessageElement<0, Type, Types...>(
Arena, LocalMessage<Type, Types...>::Offsets);
}
// Implementation of the template LocalMessage. Provides facilities for storing
// values as a Message.
template <typename Type, typename... Types>
class LocalMessage<Type, Types...> : 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<typename std::decay<Type>::type,
typename std::decay<Types>::type...>::Value;
// Offsets required to access values in Arena.
static const std::vector<size_t> 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<size_t> getOffsets(void) noexcept {
Token T = ST; // Need a mutable copy.
size_t I = 0; // Start indexing from position 0.
std::vector<size_t> 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 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 movable 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<Type, Types...>(Arena);
::operator delete(Arena);
}
// Provides an untyped pointer for the constant value at Pos.
const void *getPointerTo(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 Offsets.
template <typename Type, typename... Types>
const std::vector<size_t> LocalMessage<Type, Types...>::Offsets =
LocalMessage<Type, Types...>::getOffsets();
} // End namespace
template <typename Type, typename... Ts>
Message::Message(const Type &, const Ts &...) noexcept
: T(TypeToken<typename std::decay<Type>::type,
typename std::decay<Ts>::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 <typename Type, typename... Types>
Message::message_t Message::create(const Type &T,
const Types &... Ts) noexcept {
return message_t(new LocalMessage<Type, Types...>(T, Ts...));
}
template <typename Type, typename... Types>
Message::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 T_ = T; // NOLINT
dropNOfToken(T_, Pos);
return isHeadOfTokenTheSameType<Type>(T_);
}
template <typename Type>
const Type &Message::getValueAt(const size_t Pos) const noexcept {
ASSERT(Pos < Size && isTypeAt<Type>(Pos));
return *static_cast<const Type *>(getPointerTo(Pos));
}
} // End namespace rosa
#endif // ROSA_CORE_MESSAGE_HPP

File Metadata

Mime Type
text/x-c++
Expires
Sat, May 30, 11:49 PM (22 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
329127
Default Alt Text
Message.hpp (10 KB)

Event Timeline