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 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::Value; Log << " type number: " << PRINTABLE_TN(TN) << std::endl << " size: " << TypeForNumber::Size << std::endl << " name: " << TypeForNumber::Name << std::endl << std::endl; + Log << "Type number information of AtomConstants:" + << std::endl; + using Atom1 = AtomConstant; + using Atom2 = AtomConstant; + Log << " std::is_same::value: " + << std::is_same::value << std::endl + << " TypeNumber::Value: " + << PRINTABLE_TN(TypeNumber::Value) << std::endl + << " TypeNumber::Value: " + << PRINTABLE_TN(TypeNumber::Value) << std::endl + << " name: " << TypeForNumber::Value>::Name + << std::endl + << std::endl; + Log << "Type token information on 'TypeList':" << std::endl; // Token is generated statically. constexpr token_t Token = TypeToken::Token; STATIC_ASSERT((Token == TypeListToken>::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(T) << std::endl << " is head uint16_t: " << isHeadOfTokenTheSameType(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::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(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 struct TypeListTokenImpl; template <> struct TypeListTokenImpl { static constexpr token_t Token = 0; }; template struct TypeListTokenImpl> { + static constexpr type_nr_t TN = TypeNumber::Value; + // Check if the generated type number is valid. + STATIC_ASSERT(validTypeNumber(TN), "non-builtin type"); static constexpr token_t Token = (TypeListTokenImpl>::Token << token::RepresentationBits) | - TypeNumber::Value; + TN; }; template struct TypeListToken; template struct TypeListToken> { // NOTE: TypeNumber is computed against squased_int_t for integral types, so // let's do the same here. using List = typename SquashedTypeList>::Type; - STATIC_ASSERT((TypeListSize::Value <= token::MaxTokenizableListSize && - TypeListSubsetOf::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::Value <= token::MaxTokenizableListSize), + "too long list of types"); static constexpr token_t Token = TypeListTokenImpl::Token; }; // Convenience template turning a list of types into a TypeList to generate // TypeListToken for it. template using TypeToken = TypeListToken>; // 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(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 bool isHeadOfTokenTheSameType(const token_t Token) { ASSERT(!emptyToken(Token) && validToken(Token)); return TypeNumber::Value == typeNumberOfHeadOfToken(Token); } } // End namespace rosa #endif // ROSA_SUPPORT_TYPE_TOKEN_HPP