//ChangeLog: // 2011-01-15.1025cst // Copied from post with headers: /* From: Paul Newsgroups: gmane.comp.lib.boost.user Subject: Re: large variant performance compared (50 elements) Date: Sat, 15 Jan 2011 15:54:47 +0100 Lines: 360 */ //==================== #include #include #include #include #include #include namespace Layout { template class CLoPtrVariant { public: CLoPtrVariant() : m_uiSelect(0) { // precondition assertions BOOST_STATIC_ASSERT((boost::mpl::is_sequence::value)); } template CLoPtrVariant(const boost::shared_ptr& rspValue) { assign(rspValue); } CLoPtrVariant(const CLoPtrVariant& rOperand) { m_spSelect = rOperand.m_spSelect; m_uiSelect = rOperand.m_uiSelect; } template CLoPtrVariant(const CLoPtrVariant& rOperand) ; template CLoPtrVariant& operator=(const boost::shared_ptr& rspValue) { assign(rspValue); return *this; } template CLoPtrVariant& operator=(boost::shared_ptr& rspValue) { assign(rspValue); return *this; } bool operator<(const CLoPtrVariant& rRhs) const { if(m_uiSelect != rRhs.m_uiSelect) { return (m_uiSelect < rRhs.m_uiSelect); } else { return (m_spSelect < rRhs.m_spSelect); } } bool operator==(const CLoPtrVariant& rRhs) const { return ( m_uiSelect == rRhs.m_uiSelect && m_spSelect == rRhs.m_spSelect ); } bool operator!=(const CLoPtrVariant& rRhs) const { return !(*this == rRhs); } template typename VisitorType::result_type apply_visitor(VisitorType& rVisitor) const { typedef typename VisitorType::result_type result_type; switch (m_uiSelect) { #ifdef BOOST_PP_LOCAL_ITERATE #define BOOST_PP_LOCAL_MACRO(n) \ case n: \ return apply_visitor_impl \ < VisitorType \ , boost::mpl::int_ \ >(rVisitor); \ break; #define BOOST_PP_LOCAL_LIMITS (0, 100) //Notice increasing this number //slows down compilation times, espacially binary visitation decreases //quadratic #include BOOST_PP_LOCAL_ITERATE() default: BOOST_ASSERT(m_uiSelect); //Out of bounds; CLoPtrVariant is //missing code to access the sequence at given index, increase the //upperlimit in BOOST_PP_LOCAL_LIMITS return result_type(); #endif //BOOST_PP_LOCAL_ITERATE } } size_t GetWhich() const { return m_uiSelect; } void SetWhich(size_t which) { //LO_CHECK(!m_spSelect); m_uiSelect = which; } private: template void assign(const boost::shared_ptr& rspValue) { typedef typename boost::mpl::find < Typelist , boost::shared_ptr >::type pos_t; typedef typename boost::mpl::end < Typelist >::type end_t; BOOST_STATIC_ASSERT((!boost::is_same::value)); m_spSelect = boost::static_pointer_cast(rspValue); m_uiSelect = pos_t::pos::value; } template < typename VisitorType , typename IndexType > inline typename VisitorType::result_type apply_visitor_impl ( VisitorType& rVisitor , boost::mpl::true_ /*is_unrolled_t*/ ) const { typedef typename boost::mpl::at::type type_t; return rVisitor ( boost::static_pointer_cast ( m_spSelect ) ); } template < typename VisitorType , typename IndexType > inline typename VisitorType::result_type apply_visitor_impl ( VisitorType& rVisitor , boost::mpl::false_ /*is_unrolled_t*/ ) const { //Should never be here at runtime; only required to block code //generation that deref's the sequence out of bounds BOOST_ASSERT(false); return VisitorType::result_type(); } template < typename VisitorType , typename IndexType > inline typename VisitorType::result_type apply_visitor_impl(VisitorType& rVisitor) const { typedef typename boost::mpl::less < IndexType , typename boost::mpl::size::type >::type is_unrolled_t; return apply_visitor_impl ( rVisitor , is_unrolled_t() ); } private: boost::shared_ptr m_spSelect; size_t m_uiSelect; }; //Helper function-template to construct the variant type template struct make_variant_over { public: typedef CLoPtrVariant type; }; //Unary visitation template inline typename Visitor::result_type apply_visitor ( const Visitor& visitor , Visitable& visitable ) { return visitable.apply_visitor(visitor); } template inline typename Visitor::result_type apply_visitor ( Visitor& visitor , Visitable& visitable ) { return visitable.apply_visitor(visitor); } //Binary visitation template class CBinaryUnwrap2 { public: typedef typename Visitor::result_type result_type; private: Visitor& visitor_; Value1& value1_; public: CBinaryUnwrap2(Visitor& visitor, Value1& value1) : visitor_(visitor) , value1_(value1) { } public: template result_type operator()(Value2& value2) { return visitor_(value1_, value2); } }; template class CBinaryUnwrap1 { public: typedef typename Visitor::result_type result_type; private: Visitor& visitor_; Visitable2& visitable2_; public: CBinaryUnwrap1(Visitor& visitor, Visitable2& visitable2) : visitor_(visitor) , visitable2_(visitable2) { } public: template result_type operator()(Value1& value1) { CBinaryUnwrap2 unwrapper(visitor_, value1); return apply_visitor(unwrapper, visitable2_); } }; template inline typename Visitor::result_type apply_visitor ( const Visitor& visitor , Visitable1& visitable1 , Visitable2& visitable2 ) { CBinaryUnwrap1 unwrapper(visitor, visitable2); return apply_visitor(unwrapper, visitable1); } template inline typename Visitor::result_type apply_visitor ( Visitor& visitor , Visitable1& visitable1 , Visitable2& visitable2 ) { CBinaryUnwrap1 unwrapper(visitor, visitable2); return apply_visitor(unwrapper, visitable1); } //Base class for visitor classes template class static_visitor { public: typedef R result_type; protected: // for use as base class only static_visitor() { } ~static_visitor() { } }; template struct is_base_of_smartptr : boost::is_base_of < typename Base::value_type , typename Derived::value_type > { }; //Convert variant types template class CConvertVariant : public static_visitor<> { public: CConvertVariant(CLoPtrVariant& rVariant) : m_rVariant(rVariant) { } template < typename Pos , typename Type > void assign_variant ( boost::shared_ptr& rValue , boost::mpl::false_ ) //convertible { typedef typename boost::mpl::deref::type type_t; m_rVariant = boost::static_pointer_cast < typename type_t::value_type >(rValue); } template < typename Pos , typename Type > void assign_variant ( boost::shared_ptr& rValue , boost::mpl::true_ ) //not convertible { //BOOST_STATIC_ASSERT(boost::mpl::false_::value); //Compiler error here //indicates that (one of) the variants bounded types is not //convertible to the target variant type m_rVariant = rValue; } template void operator() ( boost::shared_ptr& rValue ) //T is not const to match the variant bounded types { typedef typename boost::mpl::find_if < Typelist , is_base_of_smartptr > >::type pos_t; typedef typename boost::mpl::end::type end_t; typedef typename boost::is_same::type not_convertible; assign_variant(rValue, not_convertible()); } private: CLoPtrVariant& m_rVariant; }; template template CLoPtrVariant:: CLoPtrVariant(const CLoPtrVariant& rOperand) { CConvertVariant convert(*this); apply_visitor(convert, rOperand); } //Delayed visitation (std algorithm support) template class CVisitDelayed { public: typedef typename VisitorType::result_type result_type; private: VisitorType& visitor_; public: explicit CVisitDelayed(VisitorType& visitor) : visitor_(visitor) { } public: //Unary template result_type operator()(Visitable& visitable) { return apply_visitor(visitor_, visitable); } //Binary template result_type operator()(Visitable1& visitable1, Visitable2& visitable2) { return apply_visitor(visitor_, visitable1, visitable2); } }; template inline CVisitDelayed apply_visitor(VisitorType& visitor) { return CVisitDelayed(visitor); } }//exit Layout namespace