diff --git a/include/rosa/deluxe/DeluxeTuple.hpp b/include/rosa/deluxe/DeluxeTuple.hpp index 9a00e25..2fcd525 100644 --- a/include/rosa/deluxe/DeluxeTuple.hpp +++ b/include/rosa/deluxe/DeluxeTuple.hpp @@ -1,349 +1,358 @@ //===-- rosa/deluxe/DeluxeTuple.hpp -----------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/deluxe/DeluxeTuple.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2019 /// /// \brief Facilities for handling multiple input/output values for connections /// in the *deluxe interface*. /// /// \see \c rosa::deluxe::DeluxeContext /// //===----------------------------------------------------------------------===// #ifndef ROSA_DELUXE_DELUXETUPLE_HPP #define ROSA_DELUXE_DELUXETUPLE_HPP #include "rosa/support/sequence.hpp" #include "rosa/support/type_token.hpp" #include #include namespace rosa { namespace deluxe { /// A tuple to manage multiple input/output values in the *deluxe interface*. /// /// \tparam Ts types of elements of the tuple /// /// \note The template may be instantiated only with built-in types and the /// number of those type may not exceed the capacity of a \c rosa::Token. template struct DeluxeTuple : public std::tuple { // Statically enforce that the class template is instantiated only with // built-in types. STATIC_ASSERT((TypeListSubsetOf, BuiltinTypes>::Value), "not built-in types"); // Statically enforce that the class template is instantiated with not too // many types. // \note Instantiation would fail on \c rosa::deluxe::DeluxeTuple::TT if there // are too any types; this assertion is for more readable error reporting. STATIC_ASSERT(sizeof...(Ts) <= token::MaxTokenizableListSize, "Too many types"); /// How many elements the instance has. static constexpr token_size_t Length = sizeof...(Ts); /// What types the class contains. /// /// Type information encoded as \c rosa::Token. static constexpr Token TT = TypeToken::Value; /// Default constructor, zero-initializes elements. DeluxeTuple(void) = default; /// Constructor, initializes the underlying \c std::tuple with lvalue /// references. /// /// \param Args value references to the values to store DeluxeTuple(const std::decay_t &... Args) : std::tuple(Args...) {} /// Constructor, initializes the underlying \c std::tuple with rvalue /// references. /// /// \param Args rvalue references to the values to store DeluxeTuple(std::decay_t &&... Args) : std::tuple(std::move(Args)...) {} /// Default copy-constructor. DeluxeTuple(const DeluxeTuple &) = default; /// Default move-constructor. DeluxeTuple(DeluxeTuple &&) = default; /// Default copy-assignment. DeluxeTuple &operator=(const DeluxeTuple &) = default; /// Default move-assignment. DeluxeTuple &operator=(DeluxeTuple &&) = default; private: /// Dumps \p this object to a given \c std::ostream. /// /// \note Provides implementation for \c rosa::deluxe::DeluxeTuple::dump. /// /// \tparam S0 Indices for accessing elements. /// /// \param [in,out] OS output stream to dump to /// /// \note The second argument provides indices statically as template /// arguments \p S0..., so its actual value is ignored. /// /// \pre Statically, \p S0... matches number of types \p this object was /// created: \code /// sizeof...(S0) == sizeof...(Ts) /// \endcode template void dump(std::ostream &OS, Seq) const noexcept; public: /// Dumps \p this object to a given \c std::ostream. /// /// \param [in,out] OS output stream to dump to void dump(std::ostream &OS) const noexcept; }; template template void DeluxeTuple::dump(std::ostream &OS, Seq) const noexcept { STATIC_ASSERT(sizeof...(S0) == sizeof...(Ts), "inconsistent type arguments"); + // Convert value to std::string with std::to_string except for a value of + // std::string that does not need conversion. + auto dump_to_string = [](const auto &V) { + if constexpr (std::is_same_v, std::string>) { + return V; + } else { + return std::to_string(V); + } + }; OS << "{"; - (OS << ... << (" " + std::to_string(std::get(*this)))); + (OS << ... << (" " + dump_to_string(std::get(*this)))); OS << " }"; } template void DeluxeTuple::dump(std::ostream &OS) const noexcept { dump(OS, seq_t()); } /// Type alias for a \c rosa::deluxe::DeluxeTuple that contains no elements. using EmptyDeluxeTuple = DeluxeTuple<>; /// Template specialization for \c rosa::deluxe::EmptyDeluxeTuple. template <> struct DeluxeTuple<> : public std::tuple<> { /// How many elements the instance has. static constexpr token_size_t Length = 0; /// What types the class contains. /// /// Type information encoded as \c rosa::Token. static constexpr Token TT = TypeToken<>::Value; /// Constructor, initializes the underlying \c std::tuple. DeluxeTuple(void) : std::tuple<>() {} /// Default copy-constructor. DeluxeTuple(const DeluxeTuple &) = default; // Default move-constructor. DeluxeTuple(DeluxeTuple &&) = default; /// Default copy-assignment. DeluxeTuple &operator=(const DeluxeTuple &) = default; // Default move-assignment, DeluxeTuple &operator=(DeluxeTuple &&) = default; /// Dumps \p this object to a given \c std::ostream. /// /// \param [in,out] OS output stream to dump to static void dump(std::ostream &OS) noexcept; }; /// Creates a \c rosa::deluxe::DeluxeTuple instance from the given lvalues /// references. /// /// \tparam Ts types of elements of the tuple /// /// \see \c rosa::deluxe::DeluxeTuple /// /// \param Args values to store in the tuple /// /// \return an instance of \c rosa::deluxe::DeluxeTuple with \p Args as /// elements template inline DeluxeTuple make_deluxe_tuple(const Ts &... Args) noexcept { return DeluxeTuple(Args...); } /// Creates a \c rosa::deluxe::DeluxeTuple instance from the given rvalue /// references. /// /// \tparam Ts types of elements of the tuple /// /// \see \c rosa::deluxe::DeluxeTuple /// /// \param Args values to store in the tuple /// /// \return an instance of \c rosa::deluxe::DeluxeTuple with \p Args as /// elements template inline DeluxeTuple make_deluxe_tuple(Ts&&... Args) noexcept { return DeluxeTuple(std::move(Args)...); } /// \defgroup UnwrapDeluxeTuple Implementation of /// rosa::deluxe::UnwrapDeluxeTuple /// /// \brief Unwraps element types from an instance of \c /// rosa::deluxe::DeluxeTuple into a \c rosa::TypeList /// /// Types can be unwrapped from a \c rosa::deluxe::DeluxeTuple instance as \code /// typename UnwrapDeluxeTuple::Type /// \endcode /// /// For example, the following expression evaluates to `true`: \code /// std::is_same_v>::Type, /// TypeList> /// \endcode ///@{ /// Declaration of the template. /// /// \tparam Tuple \c rosa::deluxe::DeluxeTuple to unwrap template struct UnwrapDeluxeTuple; /// Implementation of the template for \c rosa::deluxe::DeluxeTuple instances. template struct UnwrapDeluxeTuple> { using Type = TypeList; }; ///@} /// \defgroup TypeListUnwrapDeluxeTuple Implementation of /// \c rosa::deluxe::TypeListUnwrapDeluxeTuple /// /// \brief Unwraps element types from instances of \c /// rosa::deluxe::DeluxeTuple in a \c rosa::TypeList. /// /// Types can be unwrapped from \c rosa::deluxe::DeluxeTuple instances as \code /// typename TypeListUnwrapDeluxeTuple::Type /// \endcode /// /// For example, the following expression evaluates to `true`: \code /// std::is_same_v< /// typename TypeListUnwrapDeluxeTuple, /// T3>>::Type, /// TypeList> /// \endcode ///@{ /// Declaration of the template. /// /// \tparam List \c rosa::TypeList to check template struct TypeListUnwrapDeluxeTuple; /// Specialization for \c rosa::EmptyTypeList. template <> struct TypeListUnwrapDeluxeTuple { using Type = EmptyTypeList; }; /// Specialization for the case when the first type in \p List is an instance of /// \c rosa::deluxe::DeluxeTuple. template struct TypeListUnwrapDeluxeTuple, Ts...>> { using Type = typename TypeListConcat< typename UnwrapDeluxeTuple>::Type, typename TypeListUnwrapDeluxeTuple>::Type>::Type; }; /// Implementation for a general first type in \p List. template struct TypeListUnwrapDeluxeTuple> { using Type = typename TypeListPush< T, typename TypeListUnwrapDeluxeTuple>::Type>::Type; }; ///@} /// \defgroup IsDeluxeTuple Implementation of \c rosa::deluxe::IsDeluxeTuple /// /// \brief Tells if a type is an instance of \c rosa::deluxe::DeluxeTuple. /// /// Whether a type \c T is an instance of \c rosa::deluxe::DeluxeTuple can be /// checked as \code /// IsDeluxeTuple::Value /// \endcode ///@{ /// Declaration of the template. /// /// \tparam T type to check template struct IsDeluxeTuple; /// Specialization for the case when the type is an instance of \c /// rosa::deluxe::DeluxeTuple. template struct IsDeluxeTuple> { static constexpr bool Value = true; }; /// Implementation for a general case of type \p T. template struct IsDeluxeTuple { static constexpr bool Value = false; }; ///@} /// \defgroup TypeListAllDeluxeTuple Implementation of /// \c rosa::deluxe::TypeListAllDeluxeTuple /// /// \brief Tells if all types in a \c rosa::TypeList is an instance of \c /// rosa::deluxe::DeluxeTuple. /// /// Whether a \c rosa::TypeList \c List contains instances of \c /// rosa::deluxe::DeluxeTuple only can be checked as \code /// TypeListAllDeluxeTuple::Value /// \endcode ///@{ /// Declaration of the template. /// /// \tparam List \c rosa::TypeList to check template struct TypeListAllDeluxeTuple; /// Specialization for \c rosa::EmptyTypeList. template <> struct TypeListAllDeluxeTuple { static constexpr bool Value = true; }; /// Implementation for the general case when there is at leasst one element in /// the list. template struct TypeListAllDeluxeTuple> { static constexpr bool Value = IsDeluxeTuple::Value && TypeListAllDeluxeTuple>::Value; }; ///@} } // End namespace deluxe } // End namespace rosa namespace std { /// Dumps a \c rosa::deluxe::Deluxe instance to a given \c std::ostream. /// /// \param [in,out] OS output stream to dump to /// \param Tuple \c rosa::deluxe::Deluxe to dump /// /// \return \p OS after dumping \p Tuple to it template ostream &operator<<(ostream &OS, const rosa::deluxe::DeluxeTuple &Tuple) { Tuple.dump(OS); return OS; } } // End namespace std #endif // ROSA_DELUXE_DELUXETUPLE_HPP