Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F8448136
Message.hpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Size
16 KB
Referenced Files
None
Subscribers
None
Message.hpp
View Options
/***************************************************************************//**
*
* \file rosa/core/Message.hpp
*
* \author David Juhasz (david.juhasz@tuwien.ac.at)
*
* \date 2017
*
* \brief Declaration of `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 `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 `rosa::Message` instance remains valid
/// only as long as the owning `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 `rosa::Message`.
///
/// \pre `Type` and `Types` are all built-in types and the number of stored
/// values does not exceed `rosa::token::MaxTokenizableListSize`.
template
<
typename
Type
,
typename
...
Types
>
Message
(
const
Type
&
,
const
Types
&
...)
noexcept
;
/// No copying and moving of `rosa::Message` instances.
///@{
Message
(
const
Message
&
)
=
delete
;
Message
(
Message
&&
)
=
delete
;
Message
&
operator
=
(
const
Message
&
)
=
delete
;
Message
&
operator
=
(
Message
&&
)
=
delete
;
///@}
public
:
/// Creates a `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 `rosa::Message`
/// \param Ts optional further values to include in the `rosa::Message`
///
/// \return new `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 `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 `rosa::Message`
/// \param Ts optional further values to include in the `rosa::Message`
///
/// \return new `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 `this` object.
///
/// A valid, non-empty `rosa::Token` representing the types of the values
/// stored in `this` object.
const
Token
T
;
/// The number of values stored in `this` object.
///
/// That is the number of types encoded in `T`.
const
size_t
Size
;
/// Destroys `this` object.
virtual
~
Message
(
void
);
/// Tells if the value stored at a given index is of a given type.
///
/// \note Any `rosa::AtomConstant` is encoded in `rosa::Token` as
/// the `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 `Type`
///
/// \return if the value at index `Pos` of type `Type`
///
/// \pre `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 `Type` for the value stored at index `Pos`
///
/// \pre `Pos` is a valid index and the value at index `Pos` is of type
/// `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 `Pos`
///
/// \pre `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 `rosa::Message`, consider it
/// private.
namespace
{
/// Template class for an implementation of `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 `Arena`
///
/// \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
;
/// \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 `rosa::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 `Arena`˛
/// \param Ts optional further values to store in `Arena`
///
/// \pre `Arena` is not `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 `Arena`
///
/// \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
;
/// \defgroup createMessageElement from rvalue references
///
/// Stores values from rvalue references into a pre-allocated memory area.
///
/// \note To be used by the implementation of `rosa::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 `Arena`˛
/// \param Ts optional further values to store in `Arena`
///
/// \pre `Arena` is not `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 `rosa::createMessageElements`.
///
/// \tparam Type type of the mandatory first value stored in `Arena`
/// \tparam Types futher types whose values are stored in `Arena`
///
/// \param Arena the memory area to destroy values from
///
/// \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
;
/// \defgroup destroyMessageElement
///
/// Destroys values from a memory area.
///
/// \note To be used by the implementation of `rosa::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 `Arena` is not `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 `rosa::LocalMessage` providing facilities for
/// storing values as a `rosa::Message` object.
///
/// \tparam Type type of the first mandatory value of the `Message`
/// \tparam Types of any further values
template
<
typename
Type
,
typename
...
Types
>
class
LocalMessage
<
Type
,
Types
...
>
:
public
Message
{
public
:
/// `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 `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 `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 `Arena`.
///
/// \return `std::vector` containing byte offsets for accessing values stored
/// in `Arena`
static
std
::
vector
<
size_t
>
offsets
(
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
:
/// Creates an instance from constant lvalue references.
///
/// \param T the mandatory first value to store in the `rosa::Message` object
/// \param Ts optional further values to store in the `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 `rosa::Message` object
/// \param Ts optional further values to store in the `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 `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 `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 `rosa::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
/// `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
/// `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
T_
=
T
;
// NOLINT
dropNOfToken
(
T_
,
Pos
);
return
isHeadOfTokenTheSameType
<
Type
>
(
T_
);
}
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
Details
Attached
Mime Type
text/x-c++
Expires
Sun, May 3, 5:55 AM (15 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
314221
Default Alt Text
Message.hpp (16 KB)
Attached To
Mode
R20 SoC_Rosa_repo
Attached
Detach File
Event Timeline
Log In to Comment