Page MenuHomePhorge

No OneTemporary

Size
10 KB
Referenced Files
None
Subscribers
None
diff --git a/examples/type-facilities/type-facilities.cpp b/examples/type-facilities/type-facilities.cpp
index 2522eee..a946c91 100644
--- a/examples/type-facilities/type-facilities.cpp
+++ b/examples/type-facilities/type-facilities.cpp
@@ -1,71 +1,85 @@
/*******************************************************************************
*
* File: type-facilities.cpp
*
* Contents: An example showcasing various type-related support facilities.
*
* Copyright 2017
*
* Author: David Juhasz (david.juhasz@tuwien.ac.at)
*
******************************************************************************/
#include "rosa/config/version.h"
#include "rosa/support/log.h"
#include "rosa/support/terminal_colors.h"
#include "rosa/support/type_token.hpp"
#include <iostream>
using namespace rosa;
using namespace rosa::terminal;
int main(void) {
LOG_INFO_STREAM << library_string() << " -- " << Color::Red
<< "type facilities" << Color::Default << std::endl;
auto &Log = LOG_TRACE_STREAM << std::endl;
Log << "NumberOfBuiltinTypes: " << NumberOfBuiltinTypes << std::endl
<< "TokenBits: " << token::TokenBits << std::endl
<< "RepresentationBits: " << token::RepresentationBits << std::endl
<< "MaxTokenizableListSize: " << token::MaxTokenizableListSize
<< std::endl
<< std::endl;
Log << "Type number information on 'uint8_t':" << std::endl;
constexpr type_nr_t TN = TypeNumber<uint8_t>::Value;
Log << " type number: " << PRINTABLE_TN(TN) << std::endl
<< " size: " << TypeForNumber<TN>::Size << std::endl
<< " name: " << TypeForNumber<TN>::Name << std::endl
<< std::endl;
+ Log << "Type number information of AtomConstants:"
+ << std::endl;
+ using Atom1 = AtomConstant<atom("atom1")>;
+ using Atom2 = AtomConstant<atom("atom2")>;
+ Log << " std::is_same<Atom1, Atom2>::value: "
+ << std::is_same<Atom1, Atom2>::value << std::endl
+ << " TypeNumber<Atom1>::Value: "
+ << PRINTABLE_TN(TypeNumber<Atom1>::Value) << std::endl
+ << " TypeNumber<Atom2>::Value: "
+ << PRINTABLE_TN(TypeNumber<Atom2>::Value) << std::endl
+ << " name: " << TypeForNumber<TypeNumber<Atom1>::Value>::Name
+ << std::endl
+ << std::endl;
+
Log << "Type token information on 'TypeList<uint8_t, uint16_t>':"
<< std::endl;
// Token is generated statically.
constexpr token_t Token = TypeToken<uint8_t, uint16_t>::Token;
STATIC_ASSERT((Token == TypeListToken<TypeList<uint8_t, uint16_t>>::Token),
"alias template definition is wrong");
token_t T = Token; // We need a non-const value for dropping head later.
// Iterate over encoded entries in Token.
while (!emptyToken(T)) {
Log << " token: " << PRINTABLE_TOKEN(T) << std::endl
<< " valid: " << validToken(T) << std::endl
<< " empty: " << emptyToken(T) << std::endl
<< " full size: " << sizeOfToken(T) << std::endl
<< " head type number: " << PRINTABLE_TN(typeNumberOfHeadOfToken(T))
<< std::endl
<< " size of head: " << sizeOfHeadOfToken(T) << std::endl
<< " name of head: " << nameOfHeadOfToken(T) << std::endl
<< " is head uint8_t: " << isHeadOfTokenTheSameType<uint8_t>(T)
<< std::endl
<< " is head uint16_t: " << isHeadOfTokenTheSameType<uint16_t>(T)
<< std::endl
<< "Dropping head..." << std::endl;
dropHeadOfToken(T);
}
// Here when Token became empty.
Log << " token: " << PRINTABLE_TOKEN(T) << std::endl
<< " empty: " << emptyToken(T) << std::endl;
return 0;
}
diff --git a/include/rosa/support/type_token.hpp b/include/rosa/support/type_token.hpp
index 6d6046e..ee15d03 100644
--- a/include/rosa/support/type_token.hpp
+++ b/include/rosa/support/type_token.hpp
@@ -1,154 +1,158 @@
/******************************************************************************
*
* File: type_token.hpp
*
* Contents: Facilities for encoding TypeLists as unsigned integer values.
*
* Copyright 2017
*
* Author: David Juhasz (david.juhasz@tuwien.ac.at)
*
******************************************************************************/
#ifndef ROSA_SUPPORT_TYPE_TOKEN_HPP
#define ROSA_SUPPORT_TYPE_TOKEN_HPP
#include "rosa/support/type_numbers.hpp"
namespace rosa {
// NOTE on compatibility between different versions of the type token
// implementation:
// Different software versions produce compatible type tokens as long as
// backward compatibility of BuiltinTypes is maintained (denoted by
// TypeNumberVersion, see a note on that) and the type token implementation
// uses the same type as token_t (boiling down to the same token::TokenBits
// value) and the same 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.
// 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 token_t.
using token_t = uint64_t;
// Sanity check in case someone would change token_t.
STATIC_ASSERT(std::is_unsigned<token_t>::value,
"token_t is not an unsigned integer");
// 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 uint8_t values.
using printable_token_t = PRINTABLE(token_t);
// Helper preprocessor macro to cast tokens into printable_token_t.
#define PRINTABLE_TOKEN(T) static_cast<printable_token_t>(T)
// Nested namespace for protecting constants related to type tokens.
namespace token {
// The number of bits in one token.
constexpr size_t TokenBits = sizeof(token_t) * 8;
// The number of bits a builtin type can be uniquely encoded into, that is any
// valid 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 BuiltinTypes is
// extended.
constexpr size_t RepresentationBits = log2(NumberOfBuiltinTypes) + 1;
// Maximal size of uniquely tokenizable TypeList.
constexpr size_t MaxTokenizableListSize = TokenBits / RepresentationBits;
} // End namespace token
// Generates a token, unsigned integer representation, for the TypeList.
// NOTE: The TypeList cannot have more than MaxTokenizableListSize elements and
// must be a subset of BuiltinTypes with respect to squashed integers.
// NOTE: A generated token uniquely represents a list of types, except for
// AtomConstant types. Observe that any AtomConstant is encoded as the type
// AtomValue. The type information on all separate AtomConstant types are lost
// and replaced by the AtomValue type whose actual value needs to be considered
// in order to obtain the original AtomConstant type and so the full type
// information on the encoded TypeList.
template <typename List> struct TypeListTokenImpl;
template <> struct TypeListTokenImpl<EmptyTypeList> {
static constexpr token_t Token = 0;
};
template <typename T, typename... Ts>
struct TypeListTokenImpl<TypeList<T, Ts...>> {
+ static constexpr type_nr_t TN = TypeNumber<T>::Value;
+ // Check if the generated type number is valid.
+ STATIC_ASSERT(validTypeNumber(TN), "non-builtin type");
static constexpr token_t Token =
(TypeListTokenImpl<TypeList<Ts...>>::Token << token::RepresentationBits) |
- TypeNumber<T>::Value;
+ TN;
};
template <typename List> struct TypeListToken;
template <typename... Ts> struct TypeListToken<TypeList<Ts...>> {
// NOTE: TypeNumber is computed against squased_int_t for integral types, so
// let's do the same here.
using List = typename SquashedTypeList<TypeList<Ts...>>::Type;
- STATIC_ASSERT((TypeListSize<List>::Value <= token::MaxTokenizableListSize &&
- TypeListSubsetOf<List, BuiltinTypes>::Value),
- "not a valid list of types");
+ // Check the length of the list here.
+ // NOTE: Type validation is done one-by-one in TypeListTokenImpl.
+ STATIC_ASSERT((TypeListSize<List>::Value <= token::MaxTokenizableListSize),
+ "too long list of types");
static constexpr token_t Token = TypeListTokenImpl<List>::Token;
};
// Convenience template turning a list of types into a TypeList to generate
// TypeListToken for it.
template <typename... Ts> using TypeToken = TypeListToken<TypeList<Ts...>>;
// Anonymous namespace with helper facilities, consider it private.
namespace {
// Extracts the type number of the first encoded type of Token.
// NOTE: The returned type number is not validated.
inline type_nr_t typeNumberOfHeadOfToken(const token_t Token) {
return static_cast<type_nr_t>(Token & ((1 << token::RepresentationBits) - 1));
}
} // End namespace
// Tells if the given Token is valid, can be decoded by the current software.
// NOTE: Validation gives a correct result only when Token was generated by a
// compatible software (see note above).
bool validToken(const token_t Token);
// Tells if the token does encode an empty list.
bool emptyToken(const token_t Token);
// Tells the full memory size of the list encoded in the token.
// PRE: validToken(Token)
size_t sizeOfToken(const token_t Token);
// Tells the memory size of the first type encoded in the token.
// PRE: !empty(Token) && validToken(Token)
size_t sizeOfHeadOfToken(const token_t Token);
// Tells the name of the first type encoded in the token.
// PRE: !empty(Token) && validToken(Token)
const char *nameOfHeadOfToken(const token_t Token);
// Drops the head element of the encoded list.
void dropHeadOfToken(token_t &Token);
// Tells if the head of the encoded list is of type T.
// PRE: !empty(Token) && validToken(Token)
template <typename T>
bool isHeadOfTokenTheSameType(const token_t Token) {
ASSERT(!emptyToken(Token) && validToken(Token));
return TypeNumber<T>::Value == typeNumberOfHeadOfToken(Token);
}
} // End namespace rosa
#endif // ROSA_SUPPORT_TYPE_TOKEN_HPP

File Metadata

Mime Type
text/x-diff
Expires
Tue, Nov 11, 10:15 PM (1 d, 20 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
235937
Default Alt Text
(10 KB)

Event Timeline