Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F376178
tokenized_storages.hpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Size
21 KB
Referenced Files
None
Subscribers
None
tokenized_storages.hpp
View Options
//===-- rosa/support/tokenized_storages.hpp ---------------------*- C++ -*-===//
//
// The RoSA Framework
//
// Distributed under the terms and conditions of the Boost Software License 1.0.
// See accompanying file LICENSE.
//
// If you did not receive a copy of the license file, see
// http://www.boost.org/LICENSE_1_0.txt.
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/support/tokenized_storages.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017-2020
///
/// \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/log.h"
#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
token_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
token_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 < size()
/// \endcode
virtual
const
void
*
pointerTo
(
const
token_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
;
/// \defgroup TokenizedStorageForTypeList Implementation of
/// rosa::TokenizedStorageForTypeList
///
/// \brief Transforms a \c rosa::TypeList instance to the corresponding
/// \c rosa::TokenizedStorage instance.
///
/// A \c rosa::TypeList \c List instance can be turned into a corresponding \c
/// rosa::TokenizedStorage instance as \code
/// typename TokenizedStorageForTypeList<List>::Type
/// \endcode
///
/// For example, the following expression evaluates to `true`: \code
/// std::is_same<typename TokenizedStorageForTypeList<TypeList<T1, T2>>::Type,
/// TokenizedStorage<T1, T2>>::value
/// \endcode
///@{
/// Declaration of the template.
///
/// \tparam List \c rosa::TypeList to transform
template
<
typename
List
>
struct
TokenizedStorageForTypeList
;
/// Implementation of the template for \c rosa::TypeList instances.
template
<
typename
...
Ts
>
struct
TokenizedStorageForTypeList
<
TypeList
<
Ts
...
>>
{
using
Type
=
TokenizedStorage
<
Ts
...
>
;
};
///@}
/// 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 Types types of values to store
///
/// \param Arena pre-allocated memory area to store values to
/// \param Ts values to store in \p Arena
///
/// \pre \p Arena is not \p nullptr.
template
<
typename
...
Types
>
inline
void
createArenaElements
(
void
*
const
Arena
,
const
Types
&
...
Ts
)
noexcept
{
ASSERT
(
Arena
!=
nullptr
);
createArenaElement
<
0
>
(
Arena
,
TokenizedStorage
<
Types
...
>::
offsets
(),
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 Types types of values to store
///
/// \param Arena pre-allocated memory area to store values to
/// \param Ts values to store in \p Arena
///
/// \pre \p Arena is not \c nullptr.
template
<
typename
...
Types
>
inline
void
createArenaElements
(
void
*
const
Arena
,
Types
&&
...
Ts
)
noexcept
{
ASSERT
(
Arena
!=
nullptr
);
createArenaElement
<
0
>
(
Arena
,
TokenizedStorage
<
Types
...
>::
offsets
(),
std
::
move
(
Ts
)...);
}
/// Destroys values allocated by \c createArenaElements.
///
/// \tparam Types 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
...
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 Types types of values to destroy
///
/// \param Arena the memory area to destroy values from
///
/// \pre \p Arena is not \c nullptr.
template
<
typename
...
Types
>
inline
void
destroyArenaElements
(
void
*
const
Arena
)
noexcept
{
ASSERT
(
Arena
!=
nullptr
);
destroyArenaElement
<
0
,
Types
...
>
(
Arena
,
TokenizedStorage
<
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 Types types of values to store
template
<
typename
...
Types
>
class
TokenizedStorage
:
public
AbstractTokenizedStorage
{
public
:
/// \c rosa::Token for the stored values.
static
constexpr
Token
ST
=
TypeToken
<
std
::
decay_t
<
Types
>
...
>::
Value
;
/// Generates byte offsets for accessing values stored in
/// \c rosa::TokenizedStorage::Arena.
///
/// \note Alignment requirement of each value is taken into account.
///
/// \return \c std::vector containing byte offsets for accessing values stored
/// in \c rosa::TokenizedStorage::Arena
static
const
std
::
vector
<
size_t
>
&
offsets
(
void
)
noexcept
{
static
std
::
vector
<
size_t
>
Offsets
;
// Initialize Offsets during the first invocation.
if
(
Offsets
.
empty
())
{
Token
T
=
ST
;
// Need a mutable copy.
const
token_size_t
N
=
lengthOfToken
(
T
);
// Number of types encoded in \c T.
Offsets
.
resize
(
N
);
// Allocate proper size right away.
ASSERT
(
N
>
0
);
// Sanity check, 0 element case has a specialization.
token_size_t
I
=
0
;
// Start indexing from position \c 0.
Offsets
[
0
]
=
0
;
// First offset is always \c 0; correctly aligned.
while
(
I
<
N
-
1
)
{
ASSERT
((
size_t
)
I
+
1
<
Offsets
.
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.
const
auto
LastOffset
=
Offsets
[
I
];
auto
&
Offset
=
Offsets
[
++
I
];
const
auto
LastSize
=
sizeOfHeadOfToken
(
T
);
dropHeadOfToken
(
T
);
const
auto
CurrentAlign
=
alignmentOfHeadOfToken
(
T
);
Offset
=
LastOffset
+
LastSize
;
Offset
+=
CurrentAlign
-
1
;
Offset
&=
-
std
::
make_signed_t
<
decltype
(
CurrentAlign
)
>
(
CurrentAlign
);
}
ASSERT
((
size_t
)
I
+
1
==
Offsets
.
size
()
&&
lengthOfToken
(
T
)
==
1
);
}
return
Offsets
;
}
/// Tells the size of \c rosa::TokenizedStorage::Arena.
///
/// \note Alignment requirement of each value is taken into account.
///
/// \return size of \c rosa::TokenizedStorage::Arena to store values
static
size_t
arenaSize
(
void
)
noexcept
{
static
size_t
ArenaSize
=
0
;
// Initialize ArenaSize during first invocation.
if
(
!
ArenaSize
)
{
const
auto
&
Offsets
=
offsets
();
Token
T
=
ST
;
const
auto
N
=
lengthOfToken
(
T
);
dropNOfToken
(
T
,
N
-
1
);
// Get to the last type
// Full size is the offset for plus the size of the last value.
ArenaSize
=
Offsets
[
N
-
1
]
+
sizeOfHeadOfToken
(
T
);
}
return
ArenaSize
;
}
private
:
/// A BLOB storing all the values one after the other with necessary padding
/// for correct alignment.
void
*
const
Arena
;
public
:
/// Creates an instance with default values.
///
/// \note This constructor requires that all actual template arguments \p
/// Types... are default constructible.
TokenizedStorage
(
void
)
noexcept
:
Arena
(
::
operator
new
(
arenaSize
()))
{
ASSERT
(
Arena
!=
nullptr
);
// Sanity check.
createArenaElements
(
Arena
,
Types
()...);
}
/// Creates an instance from constant lvalue references.
///
/// \param Ts values to store
TokenizedStorage
(
const
std
::
decay_t
<
Types
>
&
...
Ts
)
noexcept
:
Arena
(
::
operator
new
(
arenaSize
()))
{
ASSERT
(
Arena
!=
nullptr
);
// Sanity check.
createArenaElements
(
Arena
,
Ts
...);
}
/// Creates an instance from rvalue references.
///
/// \param Ts values to store
TokenizedStorage
(
std
::
decay_t
<
Types
>
&&
...
Ts
)
noexcept
:
Arena
(
::
operator
new
(
arenaSize
()))
{
ASSERT
(
Arena
!=
nullptr
);
// Sanity check.
createArenaElements
(
Arena
,
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
<
std
::
decay_t
<
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
token_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
token_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 < size()
/// \endcode
const
void
*
pointerTo
(
const
token_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 < 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 T 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
>
T
&
valueAt
(
const
token_size_t
Pos
)
noexcept
{
ASSERT
(
Pos
<
size
()
&&
isTypeAt
<
T
>
(
Pos
));
return
*
static_cast
<
T
*>
(
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 T 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
T
&
valueAt
(
const
token_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
);
}
};
/// Specialization of the template \c rosa::TokenizedStorage for storing
/// nothing.
///
/// \note The specialization implements the interface defined by \c
/// rosa::AbstractTokenizedStorage but most of the functions cannot be called
/// because nothing is stored in instances of the class.
template
<>
class
TokenizedStorage
<>
:
public
AbstractTokenizedStorage
{
public
:
/// \c rosa::Token for the stored values.
static
constexpr
Token
ST
=
TypeToken
<>::
Value
;
/// Creates an instance.
TokenizedStorage
(
void
)
noexcept
=
default
;
/// 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
)
override
{}
/// Tells how many values are stored in \p this object.
///
/// \return `0`
size_t
size
(
void
)
const
noexcept
override
{
return
0
;
}
/// Tells the type of the value stored at a position.
///
/// \pre Do not call.
TypeNumber
typeAt
(
const
token_size_t
)
const
noexcept
override
{
LOG_ERROR
(
"Called unsupported function"
);
return
TypeNumber
(
0
);
}
/// Provides an untyped pointer for the value stored at a position.
///
/// \pre Do not call.
void
*
pointerTo
(
const
token_size_t
)
noexcept
override
{
LOG_ERROR
(
"Called unsupported function"
);
return
nullptr
;
}
/// Provides a constant untyped pointer for the value stored at a position.
///
/// \pre Do not call.
const
void
*
pointerTo
(
const
token_size_t
)
const
noexcept
override
{
LOG_ERROR
(
"Called unsupported function"
);
return
nullptr
;
}
/// Tells if the value stored at a given index is of a given type.
///
/// \pre Do not call.
template
<
typename
>
bool
isTypeAt
(
const
size_t
)
const
noexcept
{
LOG_ERROR
(
"Called unsupported function"
);
return
false
;
}
/// Gives a reference of a value of a given type stored at a given index.
///
/// \tparam T type to give a reference of
/// \pre Do not call.
template
<
typename
T
>
T
&
valueAt
(
const
token_size_t
)
noexcept
{
LOG_ERROR
(
"Called unsupported function"
);
return
*
static_cast
<
T
*>
(
nullptr
);
}
/// Gives a constant reference of a value of a given type stored at a given
/// index.
///
/// \tparam T type to give a reference of
///
/// \pre Do not call.
template
<
typename
T
>
const
T
&
valueAt
(
const
token_size_t
)
const
noexcept
{
LOG_ERROR
(
"Called unsupported function"
);
// \note Just use the non-const implementation as that does not modify
// \p this object.
return
*
static_cast
<
T
*>
(
nullptr
);
}
};
}
// End namespace rosa
#endif
// ROSA_SUPPORT_TOKENIZED_STORAGES_HPP
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Sun, Jun 8, 8:22 PM (1 d, 7 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
150516
Default Alt Text
tokenized_storages.hpp (21 KB)
Attached To
Mode
R20 SoC_Rosa_repo
Attached
Detach File
Event Timeline
Log In to Comment