Page MenuHomePhorge

No OneTemporary

Size
13 KB
Referenced Files
None
Subscribers
None
diff --git a/include/rosa/support/type_token.hpp b/include/rosa/support/type_token.hpp
index 7d9643e..32794c8 100644
--- a/include/rosa/support/type_token.hpp
+++ b/include/rosa/support/type_token.hpp
@@ -1,325 +1,348 @@
//===-- rosa/support/type_token.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/type_token.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
-/// \date 2017-2020
+/// \date 2017-2021
///
/// \brief Facilities for encoding TypeLists as unsigned integer values.
///
/// \note **On the compatibility between different versions of the type token
/// implementation:**
/// Different software versions produce compatible type tokens as long as
/// *backward compatibility* of \c rosa::BuiltinTypes is maintained (denoted by
/// \c rosa::TypeNumberVersion) and the type token implementation uses the same
/// type as \c rosa::token_t (boiling down to the same \c rosa::token::TokenBits
-/// value) and the same \c rosa::token::RepresentationBits value. Thus,
-/// interacting software need to cross-validate the aforementioned values to
-/// check compatibility. Interoperation between compatible sofware is limited
-/// to backward compatiblity, that is builtin types defined in both software
-/// versions are handled correctly but a newer system may produce a type token
-/// which is invalid in an old one. Therefore, tokens obtained from a compatible
-/// remote system need to be validated.
+/// value) and the same \c rosa::token::RepresentationBits value (denoted by
+/// \c rosa::token::RepresentationVersion). Thus, interacting software need to
+/// cross-validate the aforementioned values to check compatibility.
+/// Interoperation between compatible sofware is limited to backward
+/// compatiblity, that is built-in types defined in both software versions are
+/// handled correctly but a newer system may produce a type token which is
+/// invalid in an old one. Therefore, tokens obtained from a compatible remote
+/// system need to be validated.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_SUPPORT_TYPE_TOKEN_HPP
#define ROSA_SUPPORT_TYPE_TOKEN_HPP
#include "rosa/support/type_numbers.hpp"
namespace rosa {
/// Integer type to store type tokens.
///
/// \note The trade-off between the binary overhead of type encoding and the
/// maximal size of encodable lists can be tuned by using unsigned integer types
/// of different widths as \c rosa::token_t.
using token_t = uint64_t;
/// Sanity check in case someone would change \c rosa::token_t.
STATIC_ASSERT(std::is_unsigned<token_t>::value,
"token_t is not an unsigned integer");
/// Turn \c rosa::token_t into a strongly typed enumeration.
///
/// Values of \c rosa::token_t casted to \c rosa::Token can be used in a
/// type-safe way.
enum class Token : token_t {};
/// A type to cast tokens into in order to output them to streams as
/// numbers and not ASCII-codes.
///
/// \note Use it for safety, necessary for printing \c uint8_t values.
using printable_token_t = printable_t<token_t>;
/// Casts a \c rosa::Token into \c rosa::printable_token_t.
///
/// \param T \c rosa::Token to cast
#define PRINTABLE_TOKEN(T) static_cast<printable_token_t>(T)
/// Encloses constants related to the implementation of \c rosa::Token.
namespace token {
/// The number of bits in one \c rosa::Token.
constexpr size_t TokenBits = sizeof(Token) * 8;
-/// The number of bits a builtin type can be uniquely encoded into, that is any
+/// The number of bits a built-in type can be uniquely encoded into, that is any
/// valid \c rosa::TypeNumber can fit into.
///
-/// \note There is one extra bit position added for encoding so that providing a
-/// better chance to maintain backward comaptibility when \c rosa::BuiltinTypes
-/// is extended.
-constexpr size_t RepresentationBits = log2(NumberOfBuiltinTypes) + 1;
+/// The value should be not less than the binary logarithm of
+/// \c rosa::NumberOfBuiltinTypes.
+///
+/// \note The value is defined by an integer literal so it does not directly
+/// vary with the number of built-in types. The actual value allows one extra
+/// bit position for encoding (as of the time of writing this comment), which
+/// allows for more addition to the list of \c rosa::BuiltinTypes. Changing this
+/// value breaks compatibility of type encoding. Should compatibility be broken,
+/// step \c rosa::token::RepresentationVersion below!
+constexpr size_t RepresentationBits = 5;
+
+/// Sanity check in case someone adds built-in types without adjusting
+/// \c rosa::token::RepresentationBits.
+STATIC_ASSERT(log2(NumberOfBuiltinTypes) <= RepresentationBits,
+ "Cannot encode all built-in types");
+
+/// Indicates the version number of details in \c rosa::token.
+///
+/// Software with the same version number are supposed to have
+/// compatible type encoding.
+///
+/// \sa \c rosa::token::RepresentationBits on compatibility.
+constexpr size_t RepresentationVersion = 0;
/// Maximal size of uniquely tokenizable \c rosa::TypeList.
constexpr size_t MaxTokenizableListSize = TokenBits / RepresentationBits;
} // End namespace token
/// Integer type to store length of a \c rosa::Token.
///
/// \note The narrowest unsigned integer type that is wide enough to
/// represent \c rosa::token::MaxTokenizableListSize different values.
using token_size_t = typename TypeListFind<
typename TypeListDrop<log2(token::MaxTokenizableListSize) / 8 + 1,
IntegerTypesBySize>::Type,
IsNotNoneType>::Type::Second;
/// \defgroup TypeListTokenImpl Implementation of rosa::TypeListToken
///
/// \brief Generates a \c rosa::Token for a squashed \c rosa::TypeList.
///
/// \note Only to be used by the implementation of \c rosa::TypeListToken.
///@{
/// Declaration of the template.
///
/// \tparam List \c rosa::TypeList to generate \c rosa::Token for
template <typename List> struct TypeListTokenImpl;
/// Specialization for \c rosa::EmptyTypeList.
template <> struct TypeListTokenImpl<EmptyTypeList> {
static constexpr Token Value = static_cast<Token>(0);
};
/// Specialization for a non-empty \c rosa::TypeList.
template <typename T, typename... Ts>
struct TypeListTokenImpl<TypeList<T, Ts...>> {
static constexpr TypeNumber TN = TypeNumberOf<T>::Value;
// Check if the generated type number is valid.
STATIC_ASSERT(validTypeNumber(TN), "non-builtin type");
static constexpr Token Value = static_cast<Token>(
(static_cast<token_t>(TypeListTokenImpl<TypeList<Ts...>>::Value)
<< token::RepresentationBits) |
static_cast<type_nr_t>(TN));
};
///@}
/// \name TypeListToken
///
/// \brief Generates a \c rosa::Token for a \c rosa::TypeList.
///
/// \c rosa::Token for a \c rosa::TypeList \c List can be obtained as \code
/// TypeListToken<List>::Value
/// \endcode
///
/// \note The \c rosa::TypeList cannot have more than
/// \c rosa::token::MaxTokenizableListSize elements and must be a subset of
/// \c rosa::BuiltinTypes with respect to squashed integers.
///
/// \note A generated \c rosa::Token uniquely represents a list of types, except
/// for \c rosa::AtomConstant types. Observe that any \c rosa::AtomConstant is
/// encoded as the type \c rosa::AtomValue. The type information on all separate
/// \c rosa::AtomConstant types are lost and replaced by the \c rosa::AtomValue
/// type whose actual value needs to be used in order to obtain the original
/// \c rosa::AtomConstant type and so the full type information on the encoded
/// \c rosa::TypeList.
///
///@{
/// Declaration of the template.
///
/// \tparam List \c rosa::TypeList to generate \c rosa::Token for
template <typename List> struct TypeListToken;
/// Implementation using \c rosa::TypeListTokenImpl.
template <typename... Ts> struct TypeListToken<TypeList<Ts...>> {
/// \note \c rosa::TypeNumber is computed against \c rosa::squashed_t, so let's
/// do the same here.
using List = typename SquashedTypeList<TypeList<Ts...>>::Type;
/// Check the length of the list here.
/// \note Type validation is done one-by-one in \c rosa::TypeListTokenImpl.
STATIC_ASSERT((TypeListSize<List>::Value <= token::MaxTokenizableListSize),
"too long list of types");
/// The \c rosa::Token for \p List.
static constexpr Token Value = TypeListTokenImpl<List>::Value;
};
///@}
/// Convenience template to generate \c rosa::Token for a list of types.
template <typename... Ts> using TypeToken = TypeListToken<TypeList<Ts...>>;
/// Tells if a given \c rosa::Token is valid.
///
/// A \c rosa::Token is considered valid if it can be decoded by the current
/// software.
///
-/// \note Validation gives a correct result only when \p T was generated by a
-/// compatible software.
+/// \note A \c rosa::Token generated by an incompatible version may be
+/// valid but may encode types that are different from what is decoded by the
+/// current software. That is why this validation needs to be done in connection
+/// to checking \c rosa::token::RepresentationVersion and
+/// \c rosa::TypeNumberVersion for compatibility.
///
/// \sa Note for type_token.hpp on compatibility.
///
/// \param T \c rosa::Token to validate
///
/// \return if \p T is valid
bool validToken(const Token T);
/// Tells if a \c rosa::Token does encode an empty list of types.
///
/// \param T \c rosa::Token to check
///
/// \return if \p T encodes an empty list of types
bool emptyToken(const Token T);
/// Tells how many types are encoded in a \c rosa::Token.
///
/// \param T \c rosa::Token to check
///
/// \return how many types are encoded in \p T
token_size_t lengthOfToken(const Token T);
/// Extracts the \c rosa::TypeNumber of the first encoded type of a
/// \c rosa::Token.
///
/// \note The returned type number is not validated.
///
/// \param T \c rosa::Token to take the first \c rosa::TypeNumber from
///
/// \return the first \c rosa::TypeNumber encoded in \p T
inline TypeNumber headOfToken(const Token T) {
return static_cast<TypeNumber>(static_cast<token_t>(T) &
((1 << token::RepresentationBits) - 1));
}
/// Tells the memory size of the first type encoded in a \c rosa::Token.
///
/// \param T \c rosa::Token to check the first encoded type of
///
/// \return memory size of the first type encoded in \p T
///
/// \pre \p T is not empty and valid:\code
/// !empty(T) && validToken(T)
/// \endcode
size_t sizeOfHeadOfToken(const Token T);
/// Tells the required memory alignment of the first type encoded in a \c
/// rosa::Token.
///
/// \param T \c rosa::Token to check the first encoded type of
///
/// \return memory alignment of the first type encoded in \p T
///
/// \pre \p T is not empty and valid:\code
/// !empty(T) && validToken(T)
/// \endcode
size_t alignmentOfHeadOfToken(const Token T);
/// Gives the textual representation of the first type encoded in a
/// \c rosa::Token.
///
/// \param T \c rosa::Token to take the name of its first encoded type
///
/// \return textual representation of the first type encoded in \p T
///
/// \pre \p T is not empty and valid:\code
/// !empty(T) && validToken(T)
/// \endcode
const char *nameOfHeadOfToken(const Token T);
/// Updates a \c rosa::Token by dropping its first encoded type.
///
/// \param [in,out] T \c rosa::Token to drop the first encoded type of
void dropHeadOfToken(Token &T);
/// Updates a \c rosa::Token by dropping a number of its first encoded types
///
/// \param [in,out] T \c rosa::Token to drop the first \p N encoded types of
/// \param N the number of types to drop from \p T
void dropNOfToken(Token &T, const size_t N);
/// Tells what type is encoded at Position \p Pos in the \c rosa::Token \p T
///
/// \param T \c rosa::Token to check
/// \param Pos the position to check
///
/// \return \c rosa::TypeNumber of the type encodeded at position \p Pos of \c
/// rosa::Token \p T
///
/// \pre \p T is valid and it encodes \p Pos types: \code
/// validToken(T) && Pos < static_cast<size_t>(lengthOfToken(T))
/// \endcode
inline TypeNumber typeAtPositionOfToken(const Token T, const size_t Pos) {
ASSERT(validToken(T) && Pos < static_cast<size_t>(lengthOfToken(T)));
Token TT = T;
dropNOfToken(TT, Pos);
return headOfToken(TT);
}
/// Tells if the first encoded type of a \c rosa::Token is a given type.
///
/// \tparam Type type to match the first encoded type of \p T against
///
/// \param T \c rosa::Token whose first encoded type is to be matched against
/// \p Type
///
/// \return if the first encoded type of \p T is \p Type
///
/// \pre \p T is not empty and valid:\code
/// !empty(T) && validToken(T)
/// \endcode
template <typename Type> bool isHeadOfTokenTheSameType(const Token T) {
ASSERT(!emptyToken(T) && validToken(T));
return TypeNumberOf<Type>::Value == headOfToken(T);
}
} // End namespace rosa
namespace std {
/// Converts a \c rosa::Token into \c std::string.
///
/// \param T \c rosa::Token to convert
///
/// \return \c std::string representing \p T
inline string to_string(const rosa::Token T) {
return to_string(static_cast<rosa::token_t>(T));
}
/// Dumps a \c rosa::Token to a given \c std::ostream.
///
/// \param [in,out] OS output stream to dump to
/// \param T \c rosa::Token to dump
///
/// \return \p OS after dumping \p N to it
inline ostream &operator<<(ostream &OS, const rosa::Token &T) {
OS << to_string(T);
return OS;
}
} // End namespace std
#endif // ROSA_SUPPORT_TYPE_TOKEN_HPP

File Metadata

Mime Type
text/x-diff
Expires
Sat, May 17, 4:00 AM (14 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
141498
Default Alt Text
(13 KB)

Event Timeline