Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F1497450
tokenized_storages.hpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Size
17 KB
Referenced Files
None
Subscribers
None
tokenized_storages.hpp
View Options
//===-- rosa/support/tokenized_storages.hpp ---------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/support/tokenized_storages.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017
///
/// \brief Definition of storage helper template for storing values in a
/// type-safe way based on type tokens.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_SUPPORT_TOKENIZED_STORAGES_HPP
#define ROSA_SUPPORT_TOKENIZED_STORAGES_HPP
#include
"rosa/support/type_token.hpp"
#include
<memory>
#include
<vector>
namespace
rosa
{
/// Defines a simple interface for storing and accessing values of different
/// types.
///
/// While the interface provides features to access values and know their
/// types, it is the users responsibility to use particular values according to
/// their actual types. No facilities for type-safe access of values is
/// provided by the class.
///
/// \see \c rosa::TokenizedStorage for a type-safe specialization of the
/// interface.
class
AbstractTokenizedStorage
{
protected
:
/// Protected constructor restricts instantiation for derived classes.
AbstractTokenizedStorage
(
void
)
noexcept
=
default
;
public
:
/// No copying and moving of \c rosa::AbstractTokenizedStorage instances.
///@{
AbstractTokenizedStorage
(
const
AbstractTokenizedStorage
&
)
=
delete
;
AbstractTokenizedStorage
&
operator
=
(
const
AbstractTokenizedStorage
&
)
=
delete
;
AbstractTokenizedStorage
(
AbstractTokenizedStorage
&&
Other
)
=
delete
;
AbstractTokenizedStorage
&
operator
=
(
AbstractTokenizedStorage
&&
)
=
delete
;
///@}
/// Destroys \p this object.
virtual
~
AbstractTokenizedStorage
(
void
)
noexcept
=
default
;
/// Tells how many values are stored in \p this object.
///
/// \return number of values stored in \p this object
virtual
size_t
size
(
void
)
const
noexcept
=
0
;
/// Tells the type of the value stored at a position.
///
/// \param Pos the index of the value whose type is to returned
///
/// \return \c rosa::TypeNumber for the value stored at index \p Pos
///
/// \pre \p Pos is a valid index:\code
/// Pos < size()
/// \endcode
virtual
TypeNumber
typeAt
(
const
size_t
Pos
)
const
noexcept
=
0
;
/// Provides an untyped pointer for the value stored at a position.
///
/// \param Pos the index of the value to return an untyped 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
void
*
pointerTo
(
const
size_t
Pos
)
noexcept
=
0
;
/// Provides a constant untyped pointer for the value stored at a position.
///
/// \param Pos the index of the value to return an untyped pointer for
///
/// \return constant untyped pointer for the value stored at index \p Pos
///
/// \pre \p Pos is a valid index:\code
/// Pos < Offsets.size()
/// \endcode
virtual
const
void
*
pointerTo
(
const
size_t
Pos
)
const
noexcept
=
0
;
};
/// Template class storing values and providing dynamic type-safe access to
/// them in a lightweight way based on type tokens.
///
/// \see rosa/support/type_token.hpp
///
/// \tparam Types types whose values are to be stored
template
<
typename
...
Types
>
class
TokenizedStorage
;
/// Nested namespace with implementation for \c rosa::TokenizedStorage, consider
/// it private.
namespace
{
/// 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
createArenaElements
(
void
*
const
Arena
,
const
Types
&
...
Ts
)
noexcept
;
/// \defgroup createLvalueArenaElement Implementation of creating lvalue arena elements
///
/// Stores values from constant lvalue references into a pre-allocated memory
/// area.
///
/// \note To be used by the implementation of \c createArenaElements.
///
/// \todo Document these functions.
///@{
/// \note This terminal case is used for both constant lvalue references and
/// value references.
template
<
size_t
Pos
>
inline
void
createArenaElement
(
void
*
const
,
const
std
::
vector
<
size_t
>
&
Offsets
)
{
ASSERT
(
Pos
==
Offsets
.
size
());
}
template
<
size_t
Pos
,
typename
Type
,
typename
...
Types
>
inline
void
createArenaElement
(
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
);
createArenaElement
<
Pos
+
1
>
(
Arena
,
Offsets
,
Ts
...);
}
template
<
size_t
Pos
,
AtomValue
V
,
typename
...
Types
>
inline
void
createArenaElement
(
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
;
createArenaElement
<
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
createArenaElements
(
void
*
const
Arena
,
const
Type
&
T
,
const
Types
&
...
Ts
)
noexcept
{
ASSERT
(
Arena
!=
nullptr
);
createArenaElement
<
0
>
(
Arena
,
TokenizedStorage
<
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
createArenaElements
(
void
*
const
Arena
,
Types
&&
...
Ts
)
noexcept
;
/// \defgroup createRvalueArenaElement Implementation of creating rvalue arena elements
///
/// Stores values from rvalue references into a pre-allocated memory area.
///
/// \note To be used by the implementation of \c createArenaElements.
///
/// \todo Document these functions.
///@{
template
<
size_t
Pos
,
typename
Type
,
typename
...
Types
>
inline
void
createArenaElement
(
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
));
createArenaElement
<
Pos
+
1
>
(
Arena
,
Offsets
,
std
::
move
(
Ts
)...);
}
template
<
size_t
Pos
,
AtomValue
V
,
typename
...
Types
>
inline
void
createArenaElement
(
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
;
createArenaElement
<
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
createArenaElements
(
void
*
const
Arena
,
Type
&&
T
,
Types
&&
...
Ts
)
noexcept
{
ASSERT
(
Arena
!=
nullptr
);
createArenaElement
<
0
>
(
Arena
,
TokenizedStorage
<
Type
,
Types
...
>::
Offsets
,
std
::
move
(
T
),
std
::
move
(
Ts
)...);
}
/// Destroys values allocated by \c createArenaElements.
///
/// \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
destroyArenaElements
(
void
*
const
Arena
)
noexcept
;
/// \defgroup destroyArenaElement Implementation of destroying arena elements
///
/// Destroys values from a memory area.
///
/// \note To be used by the implementation of \c destroyArenaElements.
///
/// \todo Document these functions.
///@{
template
<
size_t
Pos
>
inline
void
destroyArenaElement
(
void
*
const
,
const
std
::
vector
<
size_t
>
&
Offsets
)
noexcept
{
ASSERT
(
Pos
==
Offsets
.
size
());
}
template
<
size_t
Pos
,
typename
Type
,
typename
...
Types
>
inline
void
destroyArenaElement
(
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
();
destroyArenaElement
<
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
destroyArenaElements
(
void
*
const
Arena
)
noexcept
{
ASSERT
(
Arena
!=
nullptr
);
destroyArenaElement
<
0
,
Type
,
Types
...
>
(
Arena
,
TokenizedStorage
<
Type
,
Types
...
>::
Offsets
);
}
}
// End namespace
/// Implementation of the template \c rosa::TokenizedStorage as a
/// specialization of \c rosa::AbstractTokenizedStorage.
///
/// The class provides facilities for storing values and providing type-safe
/// access to them.
///
/// \tparam Type type of the first mandatory value to store
/// \tparam Types of any further values to store
template
<
typename
Type
,
typename
...
Types
>
class
TokenizedStorage
<
Type
,
Types
...
>
:
public
AbstractTokenizedStorage
{
public
:
/// \c rosa::Token for the stored values.
static
constexpr
Token
ST
=
TypeToken
<
typename
std
::
decay
<
Type
>::
type
,
typename
std
::
decay
<
Types
>::
type
...
>::
Value
;
/// Byte offsets to access stored values in \c rosa::TokenizedStorage::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 rosa::TokenizedStorage::Arena.
///
/// \return \c std::vector containing byte offsets for accessing values stored
/// in \c rosa::TokenizedStorage::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 with default values.
///
/// \note This constructor requires that all actual template arguments \c Type
/// and \c Types... are default constructible.
TokenizedStorage
(
void
)
noexcept
:
Arena
(
::
operator
new
(
sizeOfValuesOfToken
(
ST
)))
{
ASSERT
(
Arena
!=
nullptr
);
// Sanity check.
createArenaElements
(
Arena
,
Type
(),
Types
()...);
}
/// Creates an instance from constant lvalue references.
///
/// \param T the mandatory first value to store
/// \param Ts optional further values to store
TokenizedStorage
(
const
Type
&
T
,
const
Types
&
...
Ts
)
noexcept
:
Arena
(
::
operator
new
(
sizeOfValuesOfToken
(
ST
)))
{
ASSERT
(
Arena
!=
nullptr
);
// Sanity check.
createArenaElements
(
Arena
,
T
,
Ts
...);
}
/// Creates an instance from rvalue references.
///
/// \param T the mandatory first value to store
/// \param Ts optional further values to store
TokenizedStorage
(
Type
&&
T
,
Types
&&
...
Ts
)
noexcept
:
Arena
(
::
operator
new
(
sizeOfValuesOfToken
(
ST
)))
{
ASSERT
(
Arena
!=
nullptr
);
// Sanity check.
createArenaElements
(
Arena
,
std
::
move
(
T
),
std
::
move
(
Ts
)...);
}
/// No copying and moving of \c rosa::TokenizedStorage instances.
///
/// \note This restriction may be relaxed as moving should be easy to
/// implement, only requires the possiblity to validate Arena pointer.
///@{
TokenizedStorage
(
const
TokenizedStorage
&
)
=
delete
;
TokenizedStorage
&
operator
=
(
const
TokenizedStorage
&
)
=
delete
;
TokenizedStorage
(
TokenizedStorage
&&
Other
)
=
delete
;
TokenizedStorage
&
operator
=
(
TokenizedStorage
&&
)
=
delete
;
///@}
// Destroys \p this object.
~
TokenizedStorage
(
void
)
{
destroyArenaElements
<
Type
,
Types
...
>
(
Arena
);
::
operator
delete
(
Arena
);
}
/// Tells how many values are stored in \p this object.
///
/// \return number of values stored in \p this object
size_t
size
(
void
)
const
noexcept
override
{
return
Offsets
.
size
();
}
/// Tells the type of the value stored at a position.
///
/// \param Pos the index of the value whose type is to returned
///
/// \return \c rosa::TypeNumber for the value stored at index \p Pos
///
/// \pre \p Pos is a valid index:\code
/// Pos < size()
/// \endcode
TypeNumber
typeAt
(
const
size_t
Pos
)
const
noexcept
override
{
ASSERT
(
Pos
<
size
());
Token
TT
=
ST
;
dropNOfToken
(
TT
,
Pos
);
return
headOfToken
(
TT
);
}
/// Provides an untyped pointer for the value stored at a position.
///
/// \param Pos the index of the value to return an untyped pointer for
///
/// \return untyped pointer for the value stored at index \p Pos
///
/// \pre \p Pos is a valid index:\code
/// Pos < size()
/// \endcode
void
*
pointerTo
(
const
size_t
Pos
)
noexcept
override
{
ASSERT
(
Pos
<
size
());
return
static_cast
<
uint8_t
*>
(
Arena
)
+
Offsets
[
Pos
];
}
/// Provides a constant untyped pointer for the value stored at a position.
///
/// \param Pos the index of the value to return an untyped pointer for
///
/// \return constant untyped pointer for the value stored at index \p Pos
///
/// \pre \p Pos is a valid index:\code
/// Pos < Offsets.size()
/// \endcode
const
void
*
pointerTo
(
const
size_t
Pos
)
const
noexcept
override
{
ASSERT
(
Pos
<
size
());
return
static_cast
<
const
uint8_t
*>
(
Arena
)
+
Offsets
[
Pos
];
}
/// 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 T 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 T
///
/// \pre \p Pos is a valid index:\code
/// Pos < Offsets.size()
/// \endcode
template
<
typename
T
>
bool
isTypeAt
(
const
size_t
Pos
)
const
noexcept
{
ASSERT
(
Pos
<
size
());
Token
TT
=
ST
;
dropNOfToken
(
TT
,
Pos
);
return
isHeadOfTokenTheSameType
<
T
>
(
TT
);
}
/// Gives a reference of a value of a given type stored at a given index.
///
/// \note The constant variant of the function relies on this implementation,
/// the function may not modify \p this object!
///
/// \tparam T type to give a reference of
///
/// \param Pos index to set the reference for
///
/// \return 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 T:
/// \code
/// Pos < Size && isTypeAt<T>(Pos)
/// \endcode
template
<
typename
T
>
Type
&
valueAt
(
const
size_t
Pos
)
noexcept
{
ASSERT
(
Pos
<
size
()
&&
isTypeAt
<
Type
>
(
Pos
));
return
*
static_cast
<
Type
*>
(
pointerTo
(
Pos
));
}
/// Gives a constant reference of a value of a given type stored at a given
/// index.
///
/// \tparam T 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 T:
/// \code
/// Pos < Size && isTypeAt<T>(Pos)
/// \endcode
template
<
typename
T
>
const
Type
&
valueAt
(
const
size_t
Pos
)
const
noexcept
{
// \note Just use the non-const implementation as that does not modify
// \p this object.
return
const_cast
<
TokenizedStorage
*>
(
this
)
->
valueAt
<
T
>
(
Pos
);
}
};
// Implementation of the static member field \c rosa::TokenizedStorage::Offsets.
template
<
typename
Type
,
typename
...
Types
>
const
std
::
vector
<
size_t
>
TokenizedStorage
<
Type
,
Types
...
>::
Offsets
=
TokenizedStorage
<
Type
,
Types
...
>::
offsets
();
}
// End namespace rosa
#endif
// ROSA_SUPPORT_TOKENIZED_STORAGES_HPP
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Sun, Mar 1, 9:34 PM (1 d, 7 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
278357
Default Alt Text
tokenized_storages.hpp (17 KB)
Attached To
Mode
R20 SoC_Rosa_repo
Attached
Detach File
Event Timeline
Log In to Comment