// Copyright (c) 2006, Giovanni P. Deretta // // This code may be used under either of the following two licences: // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. OF SUCH DAMAGE. // // Or: // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_COROUTINE_TUPLE_TRAITS_HPP_20060613 #define BOOST_COROUTINE_TUPLE_TRAITS_HPP_20060613 #include #include #include #include #include #include #include #include #include namespace boost { namespace coroutines { namespace detail { /* * NOTE & FIXME: coroutine_traits relies on the fact that we can construct a * boost::tuple specifing more arguments of type null_type than * required without generating an error. This is an undocumented * 'feature' and doesn't actually work for nullary tuples, * so we need to detect this case and handle it with tuple_workaround. * If ever boost::tuple is changed (for example by switching to fusion) * tuple_workaround should be used in all cases to handle extra * parameters. * The real solution would be to have an internal tuple * type that derives from boost::tuple and handles all cases we care about. * Or better, just use Boost.Fusion. * In general the code in this file needs to be put in a better shape, * eliminating all corner cases. */ /* * A boost::tuple<> is not constructible from an arbitrary * number of null_types (while non nullary tuples are). * This class takes care of this assimmetry. */ struct tuple_workaround : boost::tuple<> { # define BOOST_COROUTINE_arg_null_typecr(z, n, unused)\ const boost::tuples::null_type& \ /**/ tuple_workaround (BOOST_PP_ENUM (BOOST_COROUTINE_ARG_MAX, BOOST_COROUTINE_arg_null_typecr, ~)){} tuple_workaround(const tuple_workaround&) {} tuple_workaround() {} # undef BOOST_COROUTINE_arg_null_typecr }; } /* detail */ // All tuple traits must be derived from this // class to be correctly recognized. struct tuple_traits_tag {}; template struct get_length { enum { length = T::length }; }; template struct is_nullary : boost::mpl::bool_::value == 0> { }; template struct is_singular : boost::mpl::bool_::value == 1> { }; // Given a tuple_traits, makes a tuple of it // Simply returns the internal tuple type, unless // the tuple is nullary, then apply the nullary tuple workaround template struct make_as_tuple : boost::mpl::if_< is_nullary, detail::tuple_workaround, T > {}; // Used to implement the next metafunction, // Splitted in two parts to satisfy the compiler. template struct step_2 : boost::mpl::eval_if< is_singular, boost::tuples::element<0, typename make_as_tuple::type >, boost::mpl::identity::type> > { }; // Given a trait class return the internal tuple type modified // as a return value. // The algorithm is as follow: // - If the tuple is nullary returns 'void'. // - If it singular returns the first type // - Else return the tuple itself. template struct make_result_type : boost::mpl::eval_if< is_nullary, boost::mpl::identity, step_2 > { }; template< BOOST_PP_ENUM_BINARY_PARAMS (BOOST_COROUTINE_ARG_MAX, typename T, = boost::tuples::null_type BOOST_PP_INTERCEPT)> struct tuple_traits : tuple_traits_tag { public: // This is the straightforward boost::tuple trait // derived from the argument list. It is not // directly used in all cases. typedef boost::tuple internal_tuple_type; // FIXME: Currently coroutine code does not use this typedef in all cases // and expect it to be equal to boost::tuples::null_type typedef boost::tuples::null_type null_type; enum {length = boost::tuples::length::value}; // Return the element at the Indext'th position in the typelist. // If the index is not less than the tuple length, it returns // null_type. template struct at : boost::mpl::eval_if_c< Index < boost::tuples::length::value, boost::tuples::element, boost::mpl::identity >{}; typedef typename make_as_tuple::type as_tuple; typedef typename make_result_type::type as_result; }; template struct is_tuple_traits : boost::is_base_of {}; } } #endif