diff --git a/include/boost/variant/variant.hpp b/include/boost/variant/variant.hpp index 0f0d6d4..e6db9b2 100644 --- a/include/boost/variant/variant.hpp +++ b/include/boost/variant/variant.hpp @@ -43,6 +43,7 @@ #include "boost/preprocessor/cat.hpp" #include "boost/preprocessor/enum.hpp" #include "boost/preprocessor/enum_params.hpp" +#include "boost/preprocessor/inc.hpp" #include "boost/preprocessor/repeat.hpp" #include "boost/type_traits/alignment_of.hpp" #include "boost/type_traits/is_const.hpp" @@ -74,6 +75,16 @@ #include "boost/mpl/void.hpp" +/////////////////////////////////////////////////////////////////////////////// +// BOOST_VARIANT_APPLY_VISITOR_STEP_SIZE +// +// Unrolls variant's visitation mechanism to reduce template instantiation +// and potentially increase runtime performance. (TODO: Investigate further.) +// +#if !defined(BOOST_VARIANT_APPLY_VISITOR_STEP_SIZE) +# define BOOST_VARIANT_APPLY_VISITOR_STEP_SIZE 5 +#endif + /////////////////////////////////////////////////////////////////////////////// // BOOST_VARIANT_MINIMIZE_SIZE // @@ -475,20 +486,20 @@ struct make_variant_list private: // helpers, for metafunction result (below) // [Define a macro to convert any void(NN) tags to mpl::void...] -# define BOOST_VARIANT_DETAIL_CONVERT_VOID(z, N,_) \ +# define BOOST_VARIANT_AUX_CONVERT_VOID(z, N,_) \ typename convert_void::type // [...so that the specified types can be passed to mpl::list...] typedef typename mpl::list< BOOST_PP_ENUM( BOOST_VARIANT_LIMIT_TYPES - , BOOST_VARIANT_DETAIL_CONVERT_VOID + , BOOST_VARIANT_AUX_CONVERT_VOID , _ ) >::type initial_result; // [...and, finally, the conversion macro can be undefined:] -# undef BOOST_VARIANT_DETAIL_CONVERT_VOID +# undef BOOST_VARIANT_AUX_CONVERT_VOID public: // metafunction result @@ -588,68 +599,173 @@ inline const T& cast_storage(const void* storage, T* = 0) return *static_cast(storage); } +/////////////////////////////////////////////////////////////////////////////// +// (detail) function template forced_return +// +// Should never be called at runtime, but (artificially) satisfies +// compile-time requirement of returning a result value. (TODO: Determine the +// most efficient way to handle this -- as below? by throwing? by recursive +// call to forced_return itself? etc.) +// + +#if !defined(BOOST_MSVC) + +namespace { + +template + BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(T) +forced_return() +{ + BOOST_ASSERT(false); + BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(T) (*dummy)() = 0; + return dummy(); +} + +} + +#else // defined(BOOST_MSVC) + +__declspec(noreturn) inline void forced_return_no_return() {}; + +template +inline + BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(T) +forced_return() +{ + BOOST_ASSERT(false); + forced_return_no_return(); +} + +#endif // BOOST_MSVC optimization + /////////////////////////////////////////////////////////////////////////////// // (detail) function template apply_visitor_impl // // Invokes the given visitor on the type in the given variant storage. // -template < - typename Which, typename T - , typename NI, typename LI - , typename Visitor, typename VoidPtrCV - > -inline - BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE( - typename Visitor::result_type - ) -apply_visitor_impl( - const int var_which - , Visitor& visitor - , VoidPtrCV storage - , mpl::true_// next_is_last - , Which* = 0, T* = 0, NI* = 0, LI* = 0 - ) +struct unrolled {}; + +template +struct apply_visitor_impl_step { - // No prior iterations matched, so variant content must be last type: - BOOST_ASSERT(var_which == Which::value); - return visitor( cast_storage(storage) ); + typedef typename mpl::apply_if< + is_same + , mpl::identity + , Iter + >::type type; + + typedef typename mpl::apply_if< + is_same //is_same + , mpl::identity + , mpl::next + >::type next_iter; + + typedef apply_visitor_impl_step< + next_iter, LastIter + > next; +}; + +template +inline + BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename Visitor::result_type) +apply_visitor_impl(Visitor& visitor, VoidPtrCV operand, T*, int) +{ + return visitor( cast_storage(operand) ); +} + +template +inline + BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename Visitor::result_type) +apply_visitor_impl(Visitor&, VoidPtrCV, unrolled*, long) +{ + // should never be here at runtime: + typedef typename Visitor::result_type result_type; + return forced_return< result_type >(); } template < - typename Which, typename T - , typename NextIt, typename LastIt + typename W, typename S + , typename Visitor, typename VPCV + > +inline + BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename Visitor::result_type) +apply_visitor_impl( + const int, Visitor&, VPCV + , mpl::true_ // is_unrolled + , W* = 0, S* = 0 + ) +{ + // should never be here at runtime: + typedef typename Visitor::result_type result_type; + return forced_return< result_type >(); +} + +template < + typename Which, typename step0 , typename Visitor, typename VoidPtrCV > inline - BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE( - typename Visitor::result_type - ) + BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename Visitor::result_type) apply_visitor_impl( - const int var_which - , Visitor& visitor - , VoidPtrCV storage - , mpl::false_// next_is_last - , Which* = 0, T* = 0, NextIt* = 0, LastIt* last_it = 0 + const int var_which, Visitor& visitor, VoidPtrCV storage + , mpl::false_ // is_unrolled + , Which* = 0, step0* = 0 ) { - // If current iteration matches variant content... - if (var_which == Which::value) + // Typedef unrolled steps and associated types... +# define BOOST_VARIANT_AUX_APPLY_VISITOR_STEP_TYPEDEF(z, N, _) \ + typedef typename BOOST_PP_CAT(step,N)::type BOOST_PP_CAT(T,N); \ + typedef typename BOOST_PP_CAT(step,N)::next \ + BOOST_PP_CAT(step, BOOST_PP_INC(N)); \ + /**/ + + BOOST_PP_REPEAT( + BOOST_VARIANT_APPLY_VISITOR_STEP_SIZE + , BOOST_VARIANT_AUX_APPLY_VISITOR_STEP_TYPEDEF + , _ + ) + +# undef BOOST_VARIANT_AUX_APPLY_VISITOR_STEP_TYPEDEF + + // ...switch on the target which-index value... + switch (var_which) { - // ...then apply visitor to the variant content: - return visitor( cast_storage(storage) ); + + // ...applying the appropriate case: +# define BOOST_VARIANT_AUX_APPLY_VISITOR_STEP_CASE(z, N, _) \ + case (Which::value + (N)): \ + return apply_visitor_impl( \ + visitor, storage, static_cast(0), 1L \ + ); \ + /**/ + + BOOST_PP_REPEAT( + BOOST_VARIANT_APPLY_VISITOR_STEP_SIZE + , BOOST_VARIANT_AUX_APPLY_VISITOR_STEP_CASE + , _ + ) + +# undef BOOST_VARIANT_AUX_APPLY_VISITOR_STEP_CASE + } - // Otherwise, tail recurse, checking next iteration: - typename mpl::next::type* next_which = 0; - typename BOOST_MPL_AUX_DEREF_WNKD(NextIt)* next_type = 0; - typedef typename mpl::next::type next_next_it_t; - next_next_it_t* next_next_it = 0; - typedef typename is_same::type next_next_is_last; + // If not handled in this iteration, continue unrolling: + typedef mpl::int_< + Which::value + (BOOST_VARIANT_APPLY_VISITOR_STEP_SIZE) + > next_which; + + typedef BOOST_PP_CAT(step, BOOST_VARIANT_APPLY_VISITOR_STEP_SIZE) + next_step; + + typedef typename next_step::type next_type; + typedef typename is_same< next_type,unrolled >::type + is_unrolled; return apply_visitor_impl( - var_which, visitor, storage, next_next_is_last() - , next_which, next_type, next_next_it, last_it + var_which, visitor, storage + , is_unrolled() + , static_cast(0), static_cast(0) ); } @@ -1418,15 +1534,16 @@ public: ) raw_apply_visitor(Visitor& visitor) { - mpl::int_<0>* first_which = 0; + typedef mpl::int_<0> first_which; typedef typename mpl::begin::type first_it; - typename BOOST_MPL_AUX_DEREF_WNKD(first_it)* first_type = 0; - typename mpl::next::type* next_it = 0; - typename mpl::end::type* last_it = 0; + typedef typename mpl::end::type last_it; + typedef detail::variant::apply_visitor_impl_step< + first_it, last_it + > first_step; return detail::variant::apply_visitor_impl( which(), visitor, active_storage(), mpl::false_() - , first_which, first_type, next_it, last_it + , static_cast(0), static_cast(0) ); } @@ -1436,15 +1553,16 @@ public: ) raw_apply_visitor(Visitor& visitor) const { - mpl::int_<0>* first_which = 0; + typedef mpl::int_<0> first_which; typedef typename mpl::begin::type first_it; - typename BOOST_MPL_AUX_DEREF_WNKD(first_it)* first_type = 0; - typename mpl::next::type* next_it = 0; - typename mpl::end::type* last_it = 0; + typedef typename mpl::end::type last_it; + typedef detail::variant::apply_visitor_impl_step< + first_it, last_it + > first_step; return detail::variant::apply_visitor_impl( which(), visitor, active_storage(), mpl::false_() - , first_which, first_type, next_it, last_it + , static_cast(0), static_cast(0) ); }