From dbcae544b06ae4f33ec40ac28dd2e439d876b24e Mon Sep 17 00:00:00 2001 From: Eric Friedman Date: Thu, 21 Aug 2003 07:16:09 +0000 Subject: [PATCH] Dramatically reduced overhead caused by recursive_variant implementation for non-recursive variants. [SVN r19720] --- .../boost/variant/detail/enable_recursive.hpp | 222 ++++++++++++++++++ .../variant/detail/enable_recursive_fwd.hpp | 119 ++++++++++ .../variant/detail/enable_recursive_stub.hpp | 130 ---------- .../variant/detail/make_variant_list.hpp | 64 +++++ include/boost/variant/recursive_variant.hpp | 189 ++++++++------- include/boost/variant/variant.hpp | 165 +++++++------ include/boost/variant/variant_fwd.hpp | 125 +++++++--- test/recursive_variant_test.cpp | 6 +- 8 files changed, 696 insertions(+), 324 deletions(-) create mode 100644 include/boost/variant/detail/enable_recursive.hpp create mode 100644 include/boost/variant/detail/enable_recursive_fwd.hpp delete mode 100644 include/boost/variant/detail/enable_recursive_stub.hpp create mode 100644 include/boost/variant/detail/make_variant_list.hpp diff --git a/include/boost/variant/detail/enable_recursive.hpp b/include/boost/variant/detail/enable_recursive.hpp new file mode 100644 index 0000000..562826d --- /dev/null +++ b/include/boost/variant/detail/enable_recursive.hpp @@ -0,0 +1,222 @@ + +#if !defined(BOOST_PP_IS_ITERATING) + +///// header body + +//----------------------------------------------------------------------------- +// boost variant/detail/enable_recursive.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2003 +// Eric Friedman +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#ifndef BOOST_VARIANT_DETAIL_ENABLE_RECURSIVE_HPP +#define BOOST_VARIANT_DETAIL_ENABLE_RECURSIVE_HPP + +#include "boost/mpl/aux_/config/ctps.hpp" + +#include "boost/variant/detail/enable_recursive_fwd.hpp" +#include "boost/variant/variant_fwd.hpp" + +#if !defined(BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT) +# include "boost/mpl/aux_/lambda_arity_param.hpp" +# include "boost/mpl/aux_/template_arity.hpp" +# include "boost/mpl/aux_/preprocessor/params.hpp" +# include "boost/mpl/aux_/preprocessor/repeat.hpp" +# include "boost/mpl/int_fwd.hpp" +# include "boost/preprocessor/cat.hpp" +# include "boost/preprocessor/arithmetic/inc.hpp" +# include "boost/preprocessor/iterate.hpp" +#else +# include "boost/mpl/apply.hpp" +# include "boost/mpl/apply_if.hpp" +# include "boost/mpl/lambda.hpp" +#endif + +#include "boost/mpl/bool_fwd.hpp" +#include "boost/mpl/if.hpp" +#include "boost/mpl/or.hpp" +#include "boost/type_traits/is_same.hpp" + +#include "boost/incomplete.hpp" + +namespace boost { +namespace detail { namespace variant { + +/////////////////////////////////////////////////////////////////////////////// +// (detail) class specialization template enable_recursive_impl +// +// Performs recursive variant substitution. +// + +#if !defined(BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT) + +template < + typename T, typename RecursiveVariant + BOOST_MPL_AUX_LAMBDA_ARITY_PARAM( + typename Arity = mpl::int_< mpl::aux::template_arity::value > + ) + > +struct enable_recursive_impl +{ + typedef T type; +}; + +template +struct enable_recursive_impl< recursive_variant_, RecursiveVariant > +{ + typedef RecursiveVariant type; +}; + +#define BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEF_IMPL(N) \ + typedef typename enable_recursive_impl< \ + BOOST_PP_CAT(U,N), RecursiveVariant \ + >::type BOOST_PP_CAT(u,N); \ + /**/ + +#define BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEF(z, N, _) \ + BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEF_IMPL( BOOST_PP_INC(N) ) \ + /**/ + +#define BOOST_PP_ITERATION_LIMITS (1,BOOST_VARIANT_RECURSIVE_VARIANT_MAX_ARITY) +#define BOOST_PP_FILENAME_1 "boost/variant/detail/enable_recursive.hpp" +#include BOOST_PP_ITERATE() + +#undef BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEF_IMPL +#undef BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEF + +#else // defined(BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT) + +template +struct rebind1 +{ +private: + typedef typename mpl::lambda< + mpl::identity + >::type le_; + +public: + typedef typename mpl::apply_if< + is_same< le_, mpl::identity > + , le_ // identity + , mpl::apply1 + >::type type; +}; + +template +struct enable_recursive_impl + : rebind1< T,RecursiveVariant > +{ +}; + +#endif // !defined(BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT) + +/////////////////////////////////////////////////////////////////////////////// +// (detail) metafunction enable_recursive +// +// Attempts recursive variant substitution and wraps with boost::incomplete +// if substituion occurs *and* NoWrapper is false_. +// + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + +template +struct enable_recursive + : enable_recursive_impl +{ +}; + +template +struct enable_recursive< T,RecursiveVariant,mpl::false_ > +{ +private: // helpers, for metafunction result (below) + + typedef typename enable_recursive_impl::type t_; + +public: // metafunction result + + // [Wrap with incomplete only if rebind really changed something:] + typedef typename mpl::if_< + is_same< t_,T > + , t_ + , boost::incomplete + >::type type; + +}; + +#else // defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + +template +struct enable_recursive +{ +private: // helpers, for metafunction result (below) + + typedef typename enable_recursive_impl::type t_; + +public: // metafunction result + + // [Wrap with incomplete only if rebind really changed something:] + typedef typename mpl::if_< + mpl::or_< NoWrapper, is_same< t_,T > > + , t_ + , boost::incomplete + >::type type; + +}; + +#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION workaround + +/////////////////////////////////////////////////////////////////////////////// +// (detail) metafunction class quoted_enable_recursive +// +// Same behavior as enable_recursive metafunction (see above). +// +template +struct quoted_enable_recursive +{ + template + struct apply + : enable_recursive + { + }; +}; + +}} // namespace detail::variant +} // namespace boost + +#endif // BOOST_VARIANT_DETAIL_ENABLE_RECURSIVE_HPP + +///// iteration, depth == 1 + +#elif BOOST_PP_ITERATION_DEPTH() == 1 +#define i BOOST_PP_FRAME_ITERATION(1) + +template < + template < BOOST_MPL_PP_PARAMS(i,typename P) > class T + , BOOST_MPL_PP_PARAMS(i,typename U) + , typename RecursiveVariant + > +struct enable_recursive_impl< + T< BOOST_MPL_PP_PARAMS(i,U) > + , RecursiveVariant + BOOST_MPL_AUX_LAMBDA_ARITY_PARAM(mpl::int_<( i )>) + > +{ +private: + BOOST_MPL_PP_REPEAT(i, BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEF, _) + +public: + typedef T< BOOST_MPL_PP_PARAMS(i,u) > type; +}; + +#undef i +#endif // BOOST_PP_IS_ITERATING diff --git a/include/boost/variant/detail/enable_recursive_fwd.hpp b/include/boost/variant/detail/enable_recursive_fwd.hpp new file mode 100644 index 0000000..e3dcd20 --- /dev/null +++ b/include/boost/variant/detail/enable_recursive_fwd.hpp @@ -0,0 +1,119 @@ +//----------------------------------------------------------------------------- +// boost variant/detail/enable_recursive_fwd.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2003 +// Eric Friedman +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#ifndef BOOST_VARIANT_DETAIL_ENABLE_RECURSIVE_FWD_HPP +#define BOOST_VARIANT_DETAIL_ENABLE_RECURSIVE_FWD_HPP + +#include "boost/mpl/aux_/config/ctps.hpp" + +#include "boost/mpl/bool_fwd.hpp" + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) +# include "boost/mpl/bool.hpp" +#else +# include "boost/type_traits/is_base_and_derived.hpp" +#endif + +namespace boost { +namespace detail { namespace variant { + +/////////////////////////////////////////////////////////////////////////////// +// (detail) tag recursive_flag +// +// Signifies that the variant should perform recursive substituion. +// + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + +template +struct recursive_flag +{ + typedef T type; +}; + +#else // defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + +struct recursive_flag_tag +{ +}; + +template +struct recursive_flag + : recursive_flag_tag +{ + typedef T type; +}; + +#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION workaround + +/////////////////////////////////////////////////////////////////////////////// +// (detail) metafunction is_recursive_flag +// +// Signifies that the variant should perform recursive substituion. +// + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + +template +struct is_recursive_flag + : mpl::false_ +{ +}; + +template +struct is_recursive_flag< recursive_flag > + : mpl::true_ +{ +}; + +#else // defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + +template +struct is_recursive_flag + : is_base_and_derived< recursive_flag_tag,T > +{ +}; + +#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION workaround + +/////////////////////////////////////////////////////////////////////////////// +// (detail) metafunction enable_recursive +// +// Attempts recursive variant substitution and wraps with boost::incomplete +// if substituion occurs *and* NoWrapper is false_. +// +template < + typename T + , typename RecursiveVariant + , typename NoWrapper = mpl::false_ + > +struct enable_recursive; + +/////////////////////////////////////////////////////////////////////////////// +// (detail) metafunction class quoted_enable_recursive +// +// Same behavior as enable_recursive metafunction (see above). +// +template < + typename RecursiveVariant + , typename NoWrapper = mpl::false_ + > +struct quoted_enable_recursive; + +}} // namespace detail::variant +} // namespace boost + +#endif // BOOST_VARIANT_DETAIL_ENABLE_RECURSIVE_FWD_HPP diff --git a/include/boost/variant/detail/enable_recursive_stub.hpp b/include/boost/variant/detail/enable_recursive_stub.hpp deleted file mode 100644 index 7f099cd..0000000 --- a/include/boost/variant/detail/enable_recursive_stub.hpp +++ /dev/null @@ -1,130 +0,0 @@ -//----------------------------------------------------------------------------- -// boost variant/detail/enable_recursive_stub.hpp header file -// See http://www.boost.org for updates, documentation, and revision history. -//----------------------------------------------------------------------------- -// -// Copyright (c) 2003 -// Eric Friedman -// -// Permission to use, copy, modify, distribute and sell this software -// and its documentation for any purpose is hereby granted without fee, -// provided that the above copyright notice appears in all copies and -// that both the copyright notice and this permission notice appear in -// supporting documentation. No representations are made about the -// suitability of this software for any purpose. It is provided "as is" -// without express or implied warranty. - -#ifndef BOOST_MPL_VARIANT_DETAIL_ENABLE_RECURSIVE_STUB_HPP -#define BOOST_MPL_VARIANT_DETAIL_ENABLE_RECURSIVE_STUB_HPP - -#include "boost/config.hpp" -#include "boost/mpl/aux_/config/ttp.hpp" - -#include "boost/incomplete_fwd.hpp" - -/////////////////////////////////////////////////////////////////////////////// -// (detail) macro BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT -// -// Defined if MPL lambda facility should be used as workaround for broken -// compilers. -// -#if defined(BOOST_NO_TEMPLATE_TEMPLATE_PARAMETERS) \ - || defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \ - && !defined(BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT) -# define BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT -#endif - -#if !defined(BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT) -# include "boost/mpl/aux_/template_arity.hpp" -# include "boost/mpl/aux_/lambda_arity_param.hpp" -# include "boost/mpl/int_fwd.hpp" -#else -# include "boost/mpl/apply.hpp" -# include "boost/mpl/apply_if.hpp" -# include "boost/mpl/identity.hpp" -# include "boost/mpl/if.hpp" -# include "boost/mpl/lambda.hpp" -# include "boost/type_traits/is_same.hpp" -#endif - -namespace boost { -namespace detail { namespace variant { - -/////////////////////////////////////////////////////////////////////////////// -// (detail) metafunction enable_recursive -// -// Enables the boost::variant<..., boost::recursive_variant, ...> syntax. -// - -#if !defined(BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT) - -// primary template (specialized in recursive_variant.hpp) -template < - typename T, typename Variant - BOOST_MPL_AUX_LAMBDA_ARITY_PARAM( - typename Arity = mpl::int_< mpl::aux::template_arity::value > - ) - > -struct enable_recursive_impl -{ - typedef T type; -}; - -#else // defined(BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT) - -template -struct rebind1 -{ -private: - typedef typename mpl::lambda< - mpl::identity - >::type le_; - -public: - typedef typename mpl::apply_if< - is_same< le_, mpl::identity > - , le_ // identity - , mpl::apply1 - >::type type; -}; - -template -struct enable_recursive_impl - : rebind1< T,Variant > -{ -}; - -#endif // BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT workaround - -template -struct enable_recursive -{ -private: // helpers, for metafunction result (below) - - typedef typename enable_recursive_impl::type t_; - -public: // metafunction result - - // [Wrap with incomplete only if rebind really changed something:] - typedef typename mpl::if_< - is_same< t_,T > - , t_ - , boost::incomplete - >::type type; - -}; - -template -struct quoted_enable_recursive -{ - template - struct apply - : enable_recursive - { - }; -}; - -}} // namespace detail::variant -} // namespace boost - -#endif // BOOST_MPL_VARIANT_DETAIL_ENABLE_RECURSIVE_STUB_HPP diff --git a/include/boost/variant/detail/make_variant_list.hpp b/include/boost/variant/detail/make_variant_list.hpp new file mode 100644 index 0000000..f6bdb87 --- /dev/null +++ b/include/boost/variant/detail/make_variant_list.hpp @@ -0,0 +1,64 @@ +//----------------------------------------------------------------------------- +// boost variant/detail/make_variant_list.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2002-2003 +// Eric Friedman, Itay Maman +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#ifndef BOOST_VARIANT_DETAIL_MAKE_VARIANT_LIST_HPP +#define BOOST_VARIANT_DETAIL_MAKE_VARIANT_LIST_HPP + +#include "boost/variant/variant_fwd.hpp" + +#include "boost/mpl/list.hpp" +#include "boost/preprocessor/cat.hpp" +#include "boost/preprocessor/enum.hpp" + +namespace boost { +namespace detail { namespace variant { + +/////////////////////////////////////////////////////////////////////////////// +// (detail) metafunction make_variant_list +// +// Provides a MPL-compatible sequence with the specified non-void types +// as arguments. +// +// Rationale: see class template convert_void (variant_fwd.hpp) and using- +// declaration workaround (below). +// +template < BOOST_VARIANT_ENUM_PARAMS(typename T) > +struct make_variant_list +{ +public: // metafunction result + + // [Define a macro to convert any void(NN) tags to mpl::void...] +# 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_AUX_CONVERT_VOID + , _ + ) + >::type type; + + // [...and, finally, the conversion macro can be undefined:] +# undef BOOST_VARIANT_AUX_CONVERT_VOID + +}; + +}} // namespace detail::variant +} // namespace boost + +#endif // BOOST_VARIANT_DETAIL_MAKE_VARIANT_LIST_HPP diff --git a/include/boost/variant/recursive_variant.hpp b/include/boost/variant/recursive_variant.hpp index d6b5ae5..48fb187 100644 --- a/include/boost/variant/recursive_variant.hpp +++ b/include/boost/variant/recursive_variant.hpp @@ -1,8 +1,3 @@ - -#if !defined(BOOST_PP_IS_ITERATING) - -///// header body - //----------------------------------------------------------------------------- // boost variant/recursive_variant.hpp header file // See http://www.boost.org for updates, documentation, and revision history. @@ -22,110 +17,144 @@ #ifndef BOOST_VARIANT_RECURSIVE_VARIANT_HPP #define BOOST_VARIANT_RECURSIVE_VARIANT_HPP -#include "boost/variant/detail/enable_recursive_stub.hpp" -#include "boost/incomplete.hpp" // only forward-declared in stub header +#include "boost/variant/variant_fwd.hpp" +#include "boost/variant/detail/enable_recursive.hpp" +#include "boost/variant/detail/make_variant_list.hpp" -#include "boost/mpl/limits/arity.hpp" -#include "boost/mpl/arg.hpp" +#include "boost/mpl/aux_/lambda_arity_param.hpp" -#if !defined(BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT) -# include "boost/mpl/aux_/lambda_arity_param.hpp" -# include "boost/mpl/int_fwd.hpp" -# include "boost/mpl/aux_/preprocessor/params.hpp" -# include "boost/mpl/aux_/preprocessor/repeat.hpp" -# include "boost/preprocessor/arithmetic/inc.hpp" -# include "boost/preprocessor/iterate.hpp" +#if !defined(BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT) +# include "boost/mpl/apply_if.hpp" +# include "boost/mpl/identity.hpp" +# include "boost/mpl/is_sequence.hpp" +# include "boost/mpl/protect.hpp" +# include "boost/mpl/transform.hpp" +#else +# include "boost/preprocessor/cat.hpp" +# include "boost/preprocessor/repeat.hpp" #endif - -/////////////////////////////////////////////////////////////////////////////// -// (detail) macro BOOST_VARIANT_RECURSIVE_VARIANT_MAX_ARITY -// -// Exposes maximum allowed arity of class templates with recursive_variant -// arguments. (That is, variant< ..., T<[1], recursive_variant, ... [N]> >.) -// -#define BOOST_VARIANT_RECURSIVE_VARIANT_MAX_ARITY \ - BOOST_MPL_METAFUNCTION_MAX_ARITY +#include "boost/mpl/bool.hpp" +#include "boost/variant/variant.hpp" namespace boost { -/////////////////////////////////////////////////////////////////////////////// -// type recursive_variant -// -// Tag type indicates where recursive variant substitution should occur. -// -typedef mpl::arg<1> - recursive_variant; +namespace detail { namespace variant { /////////////////////////////////////////////////////////////////////////////// -// (detail) class specialization template enable_recursive_impl +// (detail) metafunction specialization enable_recursive_impl // -// Enables recursive variant substitution. +// Handles embedded variant types. // #if !defined(BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT) -namespace detail { namespace variant { - -template -struct enable_recursive_impl< recursive_variant, Variant > +template < + BOOST_VARIANT_ENUM_PARAMS(typename T) + , typename RecursiveVariant + BOOST_MPL_AUX_LAMBDA_ARITY_PARAM(typename Arity) + > +struct enable_recursive_impl< + ::boost::variant< + recursive_flag< T0 > + , BOOST_VARIANT_ENUM_SHIFTED_PARAMS(T) + > + , RecursiveVariant + BOOST_MPL_AUX_LAMBDA_ARITY_PARAM(Arity) + > { - typedef Variant type; + typedef ::boost::variant< + recursive_flag< T0 > + , BOOST_VARIANT_ENUM_SHIFTED_PARAMS(T) + > type; }; -#define BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEF_IMPL(N) \ - typedef typename enable_recursive_impl< \ - BOOST_PP_CAT(U,N), Variant \ - >::type BOOST_PP_CAT(u,N); \ - /**/ +template < + BOOST_VARIANT_ENUM_PARAMS(typename T) + , typename RecursiveVariant + BOOST_MPL_AUX_LAMBDA_ARITY_PARAM(typename Arity) + > +struct enable_recursive_impl< + ::boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) > + , RecursiveVariant + BOOST_MPL_AUX_LAMBDA_ARITY_PARAM(Arity) + > +{ -#define BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEF(z, N, _) \ - BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEF_IMPL( BOOST_PP_INC(N) ) \ - /**/ +#if !defined(BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT) -#define BOOST_PP_ITERATION_LIMITS (1,BOOST_VARIANT_RECURSIVE_VARIANT_MAX_ARITY) -#define BOOST_PP_FILENAME_1 "boost/variant/recursive_variant.hpp" -#include BOOST_PP_ITERATE() +private: // helpers, for metafunction result (below) -#undef BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEF_IMPL -#undef BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEF + typedef typename mpl::apply_if< + mpl::is_sequence + , mpl::identity< T0 > + , make_variant_list< BOOST_VARIANT_ENUM_PARAMS(T) > + >::type initial_types; -}} // namespace detail::variant + typedef typename mpl::transform< + initial_types + , mpl::protect< quoted_enable_recursive > + >::type types; + +public: // metafunction result + + typedef ::boost::variant< types > type; + +#else // defined(BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT) + +private: // helpers, for metafunction result (below) + + #define BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEFS(z,N,_) \ + typedef typename enable_recursive< \ + BOOST_PP_CAT(T,N) \ + , RecursiveVariant \ + , mpl::true_ \ + >::type BOOST_PP_CAT(wknd_T,N); \ + /**/ + + BOOST_PP_REPEAT( + BOOST_VARIANT_LIMIT_TYPES + , BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEFS + , _ + ) + + #undef BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEFS + +public: // metafunction result + + typedef ::boost::variant< BOOST_VARIANT_ENUM_PARAMS(wknd_T) > type; + +#endif // BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT workaround + +}; #else // defined(BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT) // -// see detail/enable_recursive_stub.hpp for workaround. +// no specializations: embedded variants unsupported on these compilers! // #endif // !defined(BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT) +}} // namespace detail::variant + +/////////////////////////////////////////////////////////////////////////////// +// metafunction recursive_variant +// +// See docs and boost/variant/variant_fwd.hpp for more information. +// +template < BOOST_VARIANT_ENUM_PARAMS(typename T) > +struct recursive_variant +{ +public: // metafunction result + + typedef boost::variant< + detail::variant::recursive_flag< T0 > + , BOOST_VARIANT_ENUM_SHIFTED_PARAMS(T) + > type; + +}; + } // namespace boost #endif // BOOST_VARIANT_RECURSIVE_VARIANT_HPP - -///// iteration, depth == 1 - -#elif BOOST_PP_ITERATION_DEPTH() == 1 -#define i BOOST_PP_FRAME_ITERATION(1) - -template < - template < BOOST_MPL_PP_PARAMS(i,typename P) > class T - , BOOST_MPL_PP_PARAMS(i,typename U) - , typename Variant - > -struct enable_recursive_impl< - T< BOOST_MPL_PP_PARAMS(i,U) > - , Variant - BOOST_MPL_AUX_LAMBDA_ARITY_PARAM(mpl::int_<( i )>) - > -{ -private: - BOOST_MPL_PP_REPEAT(i, BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEF, _) - -public: - typedef T< BOOST_MPL_PP_PARAMS(i,u) > type; -}; - -#undef i -#endif // BOOST_PP_IS_ITERATING diff --git a/include/boost/variant/variant.hpp b/include/boost/variant/variant.hpp index e3186ef..61441e7 100644 --- a/include/boost/variant/variant.hpp +++ b/include/boost/variant/variant.hpp @@ -22,8 +22,9 @@ #include // for typeid, std::type_info #include "boost/variant/variant_fwd.hpp" +#include "boost/variant/detail/enable_recursive_fwd.hpp" +#include "boost/variant/detail/make_variant_list.hpp" #include "boost/variant/detail/visitation_impl.hpp" -#include "boost/variant/detail/enable_recursive_stub.hpp" #include "boost/variant/detail/generic_result_type.hpp" #include "boost/variant/detail/has_nothrow_move.hpp" @@ -60,12 +61,11 @@ #include "boost/mpl/int.hpp" #include "boost/mpl/is_sequence.hpp" #include "boost/mpl/iter_fold.hpp" -#include "boost/mpl/front.hpp" -#include "boost/mpl/list.hpp" #include "boost/mpl/logical.hpp" #include "boost/mpl/max_element.hpp" #include "boost/mpl/next.hpp" #include "boost/mpl/pair.hpp" +#include "boost/mpl/protect.hpp" #include "boost/mpl/remove_if.hpp" #include "boost/mpl/sizeof.hpp" #include "boost/mpl/size_t.hpp" @@ -93,6 +93,7 @@ # include "boost/mpl/O1_size.hpp" #endif + namespace boost { namespace detail { namespace variant { @@ -491,40 +492,6 @@ public: // visitor interfaces }; -/////////////////////////////////////////////////////////////////////////////// -// (detail) metafunction make_variant_list -// -// Provides a MPL-compatible sequence with the specified non-void types -// as arguments. -// -// Rationale: see class template convert_void (variant_fwd.hpp) and using- -// declaration workaround (below). -// -template < BOOST_VARIANT_ENUM_PARAMS(typename T) > -struct make_variant_list -{ -public: // metafunction result - - // [Define a macro to convert any void(NN) tags to mpl::void...] -# 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_AUX_CONVERT_VOID - , _ - ) - >::type type; - - // [...and, finally, the conversion macro can be undefined:] -# undef BOOST_VARIANT_AUX_CONVERT_VOID - -}; - -#if !defined(BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE) - /////////////////////////////////////////////////////////////////////////////// // (detail) support for MPL-Sequence initializer // @@ -532,6 +499,8 @@ public: // metafunction result // overload resolution rules on any specified set of bounded types. // +#if !defined(BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE) + // (detail) quoted metafunction make_initializer_node // // Exposes a pair whose first type is a node in the initializer hierarchy. @@ -593,6 +562,13 @@ public: // static functions }; +#else // defined(BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE) + +// +// MPL-sequence initializer cannot be supported on these compilers. +// See preprocessor_list_initializer workaround below. +// + #endif // !defined(BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE) }} // namespace detail::variant @@ -603,57 +579,76 @@ public: // static functions // See docs and boost/variant/variant_fwd.hpp for more information. // template < - BOOST_VARIANT_ENUM_PARAMS(typename T_) - > + typename T0_ +#if !defined(BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT) + , BOOST_VARIANT_ENUM_SHIFTED_PARAMS(typename T) +#elif !BOOST_WORKAROUND(BOOST_MSVC, <= 1200) + , BOOST_VARIANT_ENUM_SHIFTED_PARAMS(typename wknd_T) +#else // MSVC6 + , BOOST_VARIANT_ENUM_SHIFTED_PARAMS(typename T) +#endif + > class variant { +private: // private typedefs + + struct is_recursive + : detail::variant::is_recursive_flag + { + }; #if !defined(BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT) private: // helpers, for typedefs (below) typedef typename mpl::apply_if< - mpl::is_sequence - , mpl::identity + is_recursive + , T0_ + , mpl::identity< T0_ > + >::type T0; + + typedef typename mpl::apply_if< + mpl::is_sequence + , mpl::identity , detail::variant::make_variant_list< - BOOST_VARIANT_ENUM_PARAMS(T_) + BOOST_VARIANT_ENUM_PARAMS(T) > - >::type plain_nonrecursive_types; + >::type initial_types; public: // typedefs - typedef typename mpl::transform< - plain_nonrecursive_types - , mpl::protect< detail::variant::quoted_enable_recursive > + typedef typename mpl::apply_if< + is_recursive + , mpl::transform< + initial_types + , mpl::protect< + detail::variant::quoted_enable_recursive + > + > + , mpl::identity< initial_types > >::type types; -private: // private typedefs - - typedef typename mpl::front::type T0; - -#else // defined(BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT) +#elif !BOOST_WORKAROUND(BOOST_MSVC, <= 1200) private: // helpers, for typedefs (below) -# if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + typedef typename mpl::apply_if< + is_recursive + , T0_ + , mpl::identity< T0_ > + >::type wknd_T0; - typedef variant wknd_self_t; - - #define BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEFS(z,N,_) \ - typedef typename detail::variant::enable_recursive< \ - BOOST_PP_CAT(T_,N) \ - , wknd_self_t \ - >::type BOOST_PP_CAT(T,N); \ + #define BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEFS(z,N,_) \ + typedef typename mpl::apply_if< \ + is_recursive \ + , detail::variant::enable_recursive< \ + BOOST_PP_CAT(wknd_T,N) \ + , variant \ + > \ + , mpl::identity< BOOST_PP_CAT(wknd_T,N) > \ + >::type BOOST_PP_CAT(T,N); \ /**/ -# else // MSVC7 and below - - #define BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEFS(z,N,_) \ - typedef BOOST_PP_CAT(T_,N) BOOST_PP_CAT(T,N); \ - /**/ - -# endif // MSVC7 and below workaround - BOOST_PP_REPEAT( BOOST_VARIANT_LIMIT_TYPES , BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEFS @@ -670,24 +665,40 @@ public: // typedefs private: // static precondition assertions - // Sequences are not supported for compilers that do not support - // using declarations in templates (see below). - -# if !BOOST_WORKAROUND(BOOST_MSVC, <= 1200) - + // NOTE TO USER : + // variant< type-sequence > syntax is not supported on this compiler! + // BOOST_STATIC_ASSERT(( ::boost::mpl::not_< mpl::is_sequence >::value )); -# else // MSVC6 +#else // MSVC6 + +public: // typedefs + + typedef T0_ T0; + + typedef typename detail::variant::make_variant_list< + BOOST_VARIANT_ENUM_PARAMS(T) + >::type types; + +private: // static precondition assertions // for some reason, msvc needs following all on one line: - BOOST_STATIC_CONSTANT(bool, msvc_not_is_sequence_T0 = mpl::not_< mpl::is_sequence >::value); + BOOST_STATIC_CONSTANT(bool, msvc_not_is_recursive = mpl::not_< is_recursive >::value); + BOOST_STATIC_CONSTANT(bool, msvc_not_is_sequence_T0 = mpl::not_< mpl::is_sequence >::value); + + // NOTE TO USER : + // recursive_variant is not supported on MSVC6! + // + BOOST_STATIC_ASSERT(msvc_not_is_recursive); + + // NOTE TO USER : + // variant< type-sequence > syntax is not supported on MSVC6! + // BOOST_STATIC_ASSERT(msvc_not_is_sequence_T0); -# endif // MSVC6 workaround - -#endif // BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT +#endif // BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT and MSVC6 workaround private: // static precondition assertions, cont. diff --git a/include/boost/variant/variant_fwd.hpp b/include/boost/variant/variant_fwd.hpp index 1b51071..35d4829 100644 --- a/include/boost/variant/variant_fwd.hpp +++ b/include/boost/variant/variant_fwd.hpp @@ -18,32 +18,27 @@ #define BOOST_VARIANT_VARIANT_FWD_HPP #include "boost/config.hpp" -#include "boost/mpl/limits/list.hpp" +#include "boost/empty_fwd.hpp" +#include "boost/mpl/arg.hpp" #include "boost/mpl/void.hpp" #include "boost/preprocessor/cat.hpp" -#include "boost/preprocessor/dec.hpp" #include "boost/preprocessor/enum_params.hpp" +#include "boost/preprocessor/enum_shifted.hpp" +#include "boost/preprocessor/enum_shifted_params.hpp" #include "boost/preprocessor/repeat.hpp" -#include "boost/empty_fwd.hpp" - -#if !defined(BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE) -# include "boost/preprocessor/enum_params_with_a_default.hpp" -#else -# include "boost/preprocessor/enum_params_with_defaults.hpp" -#endif - /////////////////////////////////////////////////////////////////////////////// // macro BOOST_VARIANT_LIMIT_TYPES // // Implementation-defined preprocessor symbol describing the actual // length of variant's pseudo-variadic template parameter list. // +#include "boost/mpl/limits/list.hpp" #define BOOST_VARIANT_LIMIT_TYPES \ BOOST_MPL_LIMIT_LIST_SIZE /////////////////////////////////////////////////////////////////////////////// -// BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT +// macro BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT // // Defined if variant does not support variant syntax (see below). // @@ -51,6 +46,32 @@ # define BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT #endif +/////////////////////////////////////////////////////////////////////////////// +// macro BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT +// +// Defined if MPL lambda facility should be used as workaround for broken +// compilers. (Thus, only types w/ MPL lambda workarounds can be accepted.) +// + +#include "boost/mpl/aux_/config/ctps.hpp" +#include "boost/mpl/aux_/config/ttp.hpp" + +#if defined(BOOST_NO_TEMPLATE_TEMPLATE_PARAMETERS) \ + || defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \ + && !defined(BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT) +# define BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT +#endif + +/////////////////////////////////////////////////////////////////////////////// +// macro BOOST_VARIANT_RECURSIVE_VARIANT_MAX_ARITY +// +// Exposes maximum allowed arity of class templates with recursive_variant +// arguments. (That is, variant< ..., T<[1], recursive_variant, ... [N]> >.) +// +#include "boost/mpl/limits/arity.hpp" +#define BOOST_VARIANT_RECURSIVE_VARIANT_MAX_ARITY \ + BOOST_MPL_METAFUNCTION_MAX_ARITY + /////////////////////////////////////////////////////////////////////////////// // macro BOOST_VARIANT_ENUM_PARAMS // @@ -61,6 +82,14 @@ #define BOOST_VARIANT_ENUM_PARAMS( param ) \ BOOST_PP_ENUM_PARAMS(BOOST_VARIANT_LIMIT_TYPES, param) +/////////////////////////////////////////////////////////////////////////////// +// macro BOOST_VARIANT_ENUM_SHIFTED_PARAMS +// +// Convenience macro for enumeration of BOOST_VARIANT_LIMIT_TYPES-1 params. +// +#define BOOST_VARIANT_ENUM_SHIFTED_PARAMS( param ) \ + BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_VARIANT_LIMIT_TYPES, param) + namespace boost { @@ -101,7 +130,7 @@ struct convert_void< void_ > #if defined(BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE) -// (detail) tags voidNN -- NN defined on [0, BOOST_VARIANT_LIMIT_TYPES - 1) +// (detail) tags voidNN -- NN defined on [0, BOOST_VARIANT_LIMIT_TYPES) // // Defines void types that are each unique and specializations of // convert_void that yields mpl::void_ for each voidNN type. @@ -118,7 +147,7 @@ struct convert_void< void_ > /**/ BOOST_PP_REPEAT( - BOOST_PP_DEC(BOOST_VARIANT_LIMIT_TYPES) + BOOST_VARIANT_LIMIT_TYPES , BOOST_VARIANT_DETAIL_DEFINE_VOID_N , _ ) @@ -129,6 +158,35 @@ BOOST_PP_REPEAT( }} // namespace detail::variant +/////////////////////////////////////////////////////////////////////////////// +// (detail) macro BOOST_VARIANT_AUX_DECLARE_PARAM +// +// Template parameter list for variant and recursive_variant declarations. +// + +#if !defined(BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE) + +# define BOOST_VARIANT_AUX_DECLARE_PARAMS_IMPL(z, N, T) \ + typename BOOST_PP_CAT(T,N) = detail::variant::void_ \ + /**/ + +#else // defined(BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE) + +# define BOOST_VARIANT_AUX_DECLARE_PARAMS_IMPL(z, N, T) \ + typename BOOST_PP_CAT(T,N) = BOOST_PP_CAT(detail::variant::void,N) \ + /**/ + +#endif // BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE workaround + +#define BOOST_VARIANT_AUX_DECLARE_PARAMS \ + typename T0 = boost::empty \ + , BOOST_PP_ENUM_SHIFTED( \ + BOOST_VARIANT_LIMIT_TYPES \ + , BOOST_VARIANT_AUX_DECLARE_PARAMS_IMPL \ + , T \ + ) \ + /**/ + /////////////////////////////////////////////////////////////////////////////// // class template variant (concept inspired by Andrei Alexandrescu) // @@ -145,30 +203,29 @@ BOOST_PP_REPEAT( // or // variant<>, which is variant // -template < +template < BOOST_VARIANT_AUX_DECLARE_PARAMS > class variant; - typename First = boost::empty, +/////////////////////////////////////////////////////////////////////////////// +// metafunction recursive_variant +// +// Exposes a boost::variant with recursive_variant_ tags (below) substituted +// with the variant itself (wrapped as needed with boost::incomplete). +// +template < BOOST_VARIANT_AUX_DECLARE_PARAMS > struct recursive_variant; -#if !defined(BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE) +#undef BOOST_VARIANT_AUX_DECLARE_PARAMS_IMPL +#undef BOOST_VARIANT_AUX_DECLARE_PARAMS - BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT( - BOOST_PP_DEC(BOOST_VARIANT_LIMIT_TYPES) - , typename T - , detail::variant::void_ - ) - -#else// defined(BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE) - - BOOST_PP_ENUM_PARAMS_WITH_DEFAULTS( - BOOST_PP_DEC(BOOST_VARIANT_LIMIT_TYPES) - , typename T - , detail::variant::void//NN - ) - -#endif // BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE workaround - - > -class variant; +/////////////////////////////////////////////////////////////////////////////// +// type recursive_variant_ +// +// Tag type indicates where recursive variant substitution should occur. +// +#if !defined(BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT) + struct recursive_variant_; +#else + typedef mpl::arg<1> recursive_variant_; +#endif } // namespace boost diff --git a/test/recursive_variant_test.cpp b/test/recursive_variant_test.cpp index 833fa50..0876f60 100644 --- a/test/recursive_variant_test.cpp +++ b/test/recursive_variant_test.cpp @@ -51,10 +51,10 @@ struct vector_printer int test_main(int , char* []) { - typedef boost::variant< + typedef boost::recursive_variant< int - , std::vector - > var_t; + , std::vector + >::type var_t; std::vector vec; vec.push_back(3);