diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 8f99ea8..eb5ec40 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,3 +1,4 @@ # Add the different subdirectories add_subdirectory(basic-system) +add_subdirectory(type-facilities) diff --git a/examples/type-facilities/CMakeLists.txt b/examples/type-facilities/CMakeLists.txt new file mode 100644 index 0000000..de84c63 --- /dev/null +++ b/examples/type-facilities/CMakeLists.txt @@ -0,0 +1,4 @@ +add_executable(type-facilities type-facilities.cpp) +ROSA_add_library_dependencies(type-facilities ROSAConfig) +ROSA_add_library_dependencies(type-facilities ROSASupport) + diff --git a/examples/type-facilities/type-facilities.cpp b/examples/type-facilities/type-facilities.cpp new file mode 100644 index 0000000..2522eee --- /dev/null +++ b/examples/type-facilities/type-facilities.cpp @@ -0,0 +1,71 @@ +/******************************************************************************* + * + * 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 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/atom.hpp b/include/rosa/support/atom.hpp index 1cc0cef..d003d92 100644 --- a/include/rosa/support/atom.hpp +++ b/include/rosa/support/atom.hpp @@ -1,131 +1,129 @@ /******************************************************************************* * * File: atom.hpp * * Contents: Facility for atoms, short strings statically encoded as integers. * * Copyright 2017 * * Author: David Juhasz (david.juhasz@tuwien.ac.at) * - * This implementation is based on the Atom implementation of CAF. + * This implementation is based on the atom implementation of CAF. * TODO: Check license. * ******************************************************************************/ #ifndef ROSA_SUPPORT_ATOM_HPP #define ROSA_SUPPORT_ATOM_HPP #include "rosa/support/debug.hpp" -#include - // Atoms can be used to turn short string literals into statically generated // types. The literals may consist of at most 10 non-special characters, legal // characters are _0-9A-Za-z and the whitespace character. Special characters // are turned into whitespace, which may result in different string literals // being encoded into the same integer value, if any of those contain at least // one special character. Note that the usage of special characters in the // string literals used to create atoms cannot be checked by the compiler. // // Example: // // constexpr AtomValue NameValue = atom("name"); // using NameAtom = AtomConstant; // // [](NameAtom){ std::cout << "Argument of type NameAtom"; }(NameAtom::Value) // namespace rosa { // Maximal length of valid atom strings. constexpr size_t MaxAtomLength = 10; // Underlying integer type of atom values. using atom_t = uint64_t; // Turn atom_t into a strongly typed enumeration, so atom_t values casted to // AtomValue may be used in a type-safe way. enum class AtomValue : atom_t {}; // Anonymous namespace with implementational details, consider it private. namespace { // Encodes ASCII characters to 6-bit encoding. constexpr unsigned char AtomEncodingTable[] = { /* ..0 ..1 ..2 ..3 ..4 ..5 ..6 ..7 ..8 ..9 ..A ..B ..C ..D ..E ..F */ /* 0.. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1.. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2.. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3.. */ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 0, 0, 0, 0, /* 4.. */ 0, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, /* 5.. */ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 0, 0, 0, 0, 37, /* 6.. */ 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, /* 7.. */ 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 0, 0, 0, 0}; // Decodes 6-bit characters to ASCII constexpr char AtomDecodingTable[] = " 0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ_" "abcdefghijklmnopqrstuvwxyz"; // Encodes one character and updates the integer representation. constexpr atom_t nextInterim(atom_t Current, size_t CharCode) { return (Current << 6) | AtomEncodingTable[(CharCode <= 0x7F) ? CharCode : 0]; } // Encodes a C-string into an integer value to be used as AtomValue. constexpr atom_t atomValue(const char *CStr, atom_t Interim = 0xF) { return (*CStr == '\0') ? Interim : atomValue(CStr + 1, nextInterim(Interim, static_cast(*CStr))); } } // End namespace // Converts an AtomValue into string. std::string to_string(const AtomValue &What); // Creates an AtomValue from the given string. AtomValue atom_from_string(const std::string &S); // Creates an AtomValue from the given string literal. template constexpr AtomValue atom(char const (&Str)[Size]) { // Last character is the NULL terminator. STATIC_ASSERT(Size <= MaxAtomLength + 1, "Too many characters in atom definition"); return static_cast(atomValue(Str)); } // Lifts an AtomValue to a compile-time constant. template struct AtomConstant { constexpr AtomConstant() { // nop } // Returns the wrapped value. constexpr operator AtomValue() const { return V; } // Returns the wrapped value as an integer as type atom_t. static constexpr atom_t uint_value() { return static_cast(V); } // Returns an instance *of this constant* (*not* an `AtomValue`). static const AtomConstant Value; }; // Implementation of the static member field Value of AtomConstant. template const AtomConstant AtomConstant::Value = AtomConstant{}; // Converts an AtomConstant into string. template std::string to_string(const AtomConstant &) { return to_string(V); } } // End namespace rosa #endif // ROSA_SUPPORT_ATOM_HPP diff --git a/include/rosa/support/debug.hpp b/include/rosa/support/debug.hpp index e15e2ee..dcbed4a 100644 --- a/include/rosa/support/debug.hpp +++ b/include/rosa/support/debug.hpp @@ -1,89 +1,89 @@ /******************************************************************************* * * File: debug.hpp * * Contents: Facility for debugging * * Copyright 2017 * * Author: David Juhasz (david.juhasz@tuwien.ac.at) * ******************************************************************************/ #ifndef ROSA_SUPPORT_DEBUG_HPP #define ROSA_SUPPORT_DEBUG_HPP #include "rosa/config/config.h" -#include "rosa/support/types.hpp" +#include "rosa/support/type_helper.hpp" #include "rosa/support/terminal_colors.h" #include #include namespace rosa { // Returns an output stream to use for debugging. std::ostream &dbgs(void); // Prints an array to the ostream. template std::ostream &operator<<(std::ostream &os, const std::array &arr) { os << '['; for (unsigned I = 0; I < size; ++I) { if (I) { os << ','; } os << (PRINTABLE(T)) arr[I]; } os << ']'; return os; } } // End namespace rosa #ifndef ROSA_ENABLE_ASSERTIONS #define ASSERT(stmt) ROSA_IGNORE_UNUSED(stmt) #elif defined(ROSA_WINDOWS) #define ASSERT(stmt) \ if (static_cast(stmt) == false) { \ rosa::dbgs() << rosa::terminal::Color::Default << __FILENAME__ << ":" \ << __LINE__ << ": requirement failed: '" << #stmt << "'" \ << std::endl; \ ::abort(); \ } \ ROSA_VOID_STMT #else // defined(ROSA_LINUX) #include #define ASSERT(stmt) \ if (static_cast(stmt) == false) { \ rosa::dbgs() << rosa::terminal::Color::Default << __FILENAME__ << ":" \ << __LINE__ << ": requirement failed: '" << #stmt << "'" \ << std::endl; \ void *array[20]; \ auto bt_size = ::backtrace(array, 20); \ ::backtrace_symbols_fd(array, bt_size, 2); \ ::abort(); \ } \ ROSA_VOID_STMT #endif // defined(ROSA_ENABLE_ASSERTIONS) #ifndef NDEBUG #define DEBUG(X) \ do { \ X; \ } while (false) #define DEBUGVAR(V) \ do { \ rosa::dbgs() << rosa::terminal::Color::Default << #V << " (" \ << __FILENAME__ << ":" << __LINE__ << "): " << (V) \ << std::endl; \ } while (false) #else // defined(NDEBUG) #define DEBUG(X) ROSA_IGNORE_UNUSED(X) #define DEBUGVAR(X) ROSA_IGNORE_UNUSED(X) #endif // defined(NDEBUG) // Static assertions are always emitted to the code. #define STATIC_ASSERT(COND, DIAG) static_assert((COND), DIAG) #endif // ROSA_SUPPORT_DEBUG_HPP diff --git a/include/rosa/support/math.hpp b/include/rosa/support/math.hpp new file mode 100644 index 0000000..d2aa41c --- /dev/null +++ b/include/rosa/support/math.hpp @@ -0,0 +1,28 @@ +/******************************************************************************* + * + * File: math.hpp + * + * Contents: Math helpers. + * + * Copyright 2017 + * + * Author: David Juhasz (david.juhasz@tuwien.ac.at) + * + ******************************************************************************/ + +#ifndef ROSA_SUPPORT_MATH_HPP +#define ROSA_SUPPORT_MATH_HPP + +#include + +namespace rosa { + +// Computes log base 2 of an integer as a constexpr. +constexpr size_t log2(const size_t N) { + return ((N < 2) ? 1 : 1 + log2(N / 2)); +} + +} // End namespace rosa + +#endif // ROSA_SUPPORT_MATH_HPP + diff --git a/include/rosa/support/squashed_int.hpp b/include/rosa/support/squashed_int.hpp new file mode 100644 index 0000000..94bf918 --- /dev/null +++ b/include/rosa/support/squashed_int.hpp @@ -0,0 +1,69 @@ +/****************************************************************************** + * + * File: squashed_int.hpp + * + * Contents: Facilities for squashing integer types into standard equivalents. + * + * Copyright 2017 + * + * Author: David Juhasz (david.juhasz@tuwien.ac.at) + * + * This implementation is based on the squashed_int implementation of CAF. + * TODO: Check license. + * + ******************************************************************************/ + +#ifndef ROSA_SUPPORT_SQUASHED_INT_HPP +#define ROSA_SUPPORT_SQUASHED_INT_HPP + +#include "rosa/support/type_list.hpp" +#include "rosa/support/type_pair.hpp" + +namespace rosa { + +// Compile-time list of integer types. +// NOTE: This list is used to select a proper type as type_nr_t, +// always make sure that type_nr_t remains correct whenever changing the list. +using IntegerTypesBySize = TypeList< // bytes + unit_t, // 0 + TypePair, // 1 + TypePair, // 2 + unit_t, // 3 + TypePair, // 4 + unit_t, // 5 + unit_t, // 6 + unit_t, // 7 + TypePair // 8 + >; + +// Squashes integer types into [u]int_[8|16|32|64]_t equivalents. +template struct SquashedInt { + using TPair = typename TypeListAt::Type; + using Type = + typename std::conditional::value, typename TPair::First, + typename TPair::Second>::type; +}; + +// Convenience alias for obtaining a squashed int type. +template +using squashed_int_t = typename SquashedInt::Type; + +// Replaces all integral types with their corresponding squashed integer. +template struct SquashedTypeList; + +template <> struct SquashedTypeList { + using Type = EmptyTypeList; +}; + +template +struct SquashedTypeList> { + using SquashedT = typename std::conditional::value, + squashed_int_t, T>::type; + using Type = typename TypeListPush< + SquashedT, typename SquashedTypeList>::Type>::Type; +}; + +} // End namespace rosa + +#endif // ROSA_SUPPORT_SQUASHED_INT_HPP + diff --git a/include/rosa/support/types.hpp b/include/rosa/support/type_helper.hpp similarity index 68% copy from include/rosa/support/types.hpp copy to include/rosa/support/type_helper.hpp index 3fe00af..fc55969 100644 --- a/include/rosa/support/types.hpp +++ b/include/rosa/support/type_helper.hpp @@ -1,46 +1,50 @@ /******************************************************************************* * - * File: types.hpp + * File: type_helper.hpp * - * Contents: Facility for type-related things + * Contents: Helper facilities for type-related stuff. * - * Copyright 2016 + * Copyright 2017 * * Author: David Juhasz (david.juhasz@tuwien.ac.at) * ******************************************************************************/ -#ifndef ROSA_SUPPORT_TYPES_HPP -#define ROSA_SUPPORT_TYPES_HPP +#ifndef ROSA_SUPPORT_TYPE_HELPER_HPP +#define ROSA_SUPPORT_TYPE_HELPER_HPP #include namespace rosa { +/* ************************************************************************** * + * Printable * + * ************************************************************************** */ + // A value of type [u]int8_t is treated as a character when being put to an // output stream, which can result in invisible characters being printed. To // avoid that, such a value needs to be casted to a wider type. It can be done // by using the following template to find a target type to cast our value to. // NOTE: There is a preprocessor macro below which can be used instead of the // tedious typename stuff. template struct PrintableType { typedef T type; }; template <> struct PrintableType { typedef unsigned int type; }; template <> struct PrintableType { typedef int type; }; #define PRINTABLE(T) typename PrintableType::type } // End namespace rosa -#endif // ROSA_SUPPORT_TYPES_HPP +#endif // ROSA_SUPPORT_TYPE_HELPER_HPP diff --git a/include/rosa/support/type_list.hpp b/include/rosa/support/type_list.hpp new file mode 100644 index 0000000..1afba61 --- /dev/null +++ b/include/rosa/support/type_list.hpp @@ -0,0 +1,199 @@ +/******************************************************************************* + * + * File: type_list.hpp + * + * Contents: Facilities for types representing lists of types. + * + * Copyright 2017 + * + * Author: David Juhasz (david.juhasz@tuwien.ac.at) + * + * This implementation is partially based on the type_list implementation of + * CAF. + * TODO: Check license. + * + ******************************************************************************/ + +#ifndef ROSA_SUPPORT_TYPE_LIST_HPP +#define ROSA_SUPPORT_TYPE_LIST_HPP + +#include "rosa/support/debug.hpp" +#include "rosa/support/types.hpp" +#include + +namespace rosa { + +// A list of types. +template struct TypeList { + constexpr TypeList() { + // nop + } +}; + +// Denotes the empty list. +using EmptyTypeList = TypeList<>; + +// Gets element at index Pos of List. +template struct TypeListAtImpl; + +template +struct TypeListAtImpl { + using Type = typename TypeListAtImpl::Type; +}; + +template struct TypeListAtImpl<0, T, Ts...> { + using Type = T; +}; + +template struct TypeListAtImpl { using Type = none_t; }; + +template struct TypeListAt; + +template struct TypeListAt, Pos> { + using Type = typename TypeListAtImpl::Type; +}; + +// Finds the first element of type What beginning at index Pos. +template struct TypeListIndexOfImpl; + +template struct TypeListIndexOfImpl { + static constexpr int Value = -1; +}; + +template +struct TypeListIndexOfImpl { + static constexpr int Value = Pos; +}; + +template +struct TypeListIndexOfImpl { + static constexpr int Value = TypeListIndexOfImpl::Value; +}; + +template struct TypeListIndexOf; + +template +struct TypeListIndexOf, T> { + static constexpr int Value = TypeListIndexOfImpl<0, T, Ts...>::Value; +}; + +// Gets the first element of List. +template struct TypeListHead; + +template <> struct TypeListHead { using Type = none_t; }; + +template +struct TypeListHead> { + using Type = T; +}; + +// Gets the tail of List. +template struct TypeListTail; + +template <> struct TypeListTail> { using Type = EmptyTypeList; }; + +template +struct TypeListTail> { + using Type = TypeList; +}; + +// Extends a TypeList with a type, in the front or in the back depending on the +// order of the template arguments. +template +struct TypeListPush; + +template +struct TypeListPush, T> { + using Type = TypeList; +}; + +template +struct TypeListPush> { + using Type = TypeList; +}; + +// Drops the first N element of List. +template struct TypeListDrop; + +template struct TypeListDrop { + using Type = EmptyTypeList; +}; + +template +struct TypeListDrop> { + using Type = typename std::conditional< + N == 0, TypeList, + typename TypeListDrop>::Type>::type; +}; + +// Gets the number of template parameters of List. +template +struct TypeListSize; + +template struct TypeListSize> { + static constexpr size_t Value = sizeof...(Ts); +}; + +template constexpr size_t TypeListSize>::Value; + +// Tests whether a list is empty. +template struct TypeListEmpty { + static constexpr bool Value = std::is_same::value; +}; + +// Tells if List contains type T. +template struct TypeListContains; + +template +struct TypeListContains, T> { + static constexpr bool Value = + std::conditional, T>::Value == -1, + std::false_type, std::true_type>::type::value; +}; + +// Tells if ListA is a subset of ListB +template +struct TypeListSubsetOf; + +template +struct TypeListSubsetOf { + static constexpr bool Value = true; +}; + +template +struct TypeListSubsetOf { + static constexpr bool Value = false; +}; + +template +struct TypeListSubsetOf, List> + : TypeListSubsetOf, List, + TypeListContains::Value> {}; + +// Finds the first element satisfying Pred + +template