2
0
mirror of https://github.com/boostorg/variant.git synced 2026-02-18 02:22:14 +00:00

Added unrolling to visitation mechanism.

[SVN r19166]
This commit is contained in:
Eric Friedman
2003-07-17 06:45:55 +00:00
parent 02fb9fffbc
commit acca3a4fd9

View File

@@ -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<BOOST_PP_CAT(T,N)>::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<const T*>(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 <typename T>
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 <typename T>
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 <typename Iter, typename LastIter>
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<T>(storage) );
typedef typename mpl::apply_if<
is_same<Iter, LastIter>
, mpl::identity<unrolled>
, Iter
>::type type;
typedef typename mpl::apply_if<
is_same<type, unrolled> //is_same<Iter, LastIter>
, mpl::identity<LastIter>
, mpl::next<Iter>
>::type next_iter;
typedef apply_visitor_impl_step<
next_iter, LastIter
> next;
};
template <typename Visitor, typename VoidPtrCV, typename T>
inline
BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename Visitor::result_type)
apply_visitor_impl(Visitor& visitor, VoidPtrCV operand, T*, int)
{
return visitor( cast_storage<T>(operand) );
}
template <typename Visitor, typename VoidPtrCV>
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<T>(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<BOOST_PP_CAT(T,N)*>(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<Which>::type* next_which = 0;
typename BOOST_MPL_AUX_DEREF_WNKD(NextIt)* next_type = 0;
typedef typename mpl::next<NextIt>::type next_next_it_t;
next_next_it_t* next_next_it = 0;
typedef typename is_same<next_next_it_t, LastIt>::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<next_which*>(0), static_cast<next_step*>(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<types>::type first_it;
typename BOOST_MPL_AUX_DEREF_WNKD(first_it)* first_type = 0;
typename mpl::next<first_it>::type* next_it = 0;
typename mpl::end<types>::type* last_it = 0;
typedef typename mpl::end<types>::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<first_which*>(0), static_cast<first_step*>(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<types>::type first_it;
typename BOOST_MPL_AUX_DEREF_WNKD(first_it)* first_type = 0;
typename mpl::next<first_it>::type* next_it = 0;
typename mpl::end<types>::type* last_it = 0;
typedef typename mpl::end<types>::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<first_which*>(0), static_cast<first_step*>(0)
);
}