|
Boost Users : |
Subject: Re: [Boost-users] large variant performance compared (50 elements)
From: Paul (peebor_at_[hidden])
Date: 2011-01-15 09:54:47
It looks like we are heading for an alternative approach (again). Based
on the boost::variant i'm writing my own variant that is optimized to
only hold shared_ptr's.
First test seem promising i can finally create variants with 200 types
in 2 sec compilation :) However binary invokation is even here quickly a
problem, its generating 'paths' quadratically, 50 bounded types produce
2500 paths....
Maybe anyone can provide some feedback on following implementation?
Thanks,
Paul
template<typename Typelist>
class CLoPtrVariant
{
public:
CLoPtrVariant()
: m_uiSelect(0)
{
// precondition assertions
BOOST_STATIC_ASSERT((boost::mpl::is_sequence<Typelist>::value));
}
template<typename Type>
CLoPtrVariant(const boost::shared_ptr<Type>& rspValue)
{
assign(rspValue);
}
CLoPtrVariant(const CLoPtrVariant& rOperand)
{
m_spSelect = rOperand.m_spSelect;
m_uiSelect = rOperand.m_uiSelect;
}
template<typename Typelist2>
CLoPtrVariant(const CLoPtrVariant<Typelist2>& rOperand)
{
CConvertVariant<Typelist> convert(*this);
apply_visitor(convert, rOperand);
}
template<typename Type>
CLoPtrVariant& operator=(const boost::shared_ptr<Type>& rspValue)
{
assign(rspValue);
return *this;
}
template<typename Type>
CLoPtrVariant& operator=(boost::shared_ptr<Type>& 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>
typename VisitorType::result_type apply_visitor(VisitorType&
rVisitor) const
{
switch (m_uiSelect)
{
#ifdef BOOST_PP_LOCAL_ITERATE
#define BOOST_PP_LOCAL_MACRO(n) \
case n: \
return apply_visitor_impl<VisitorType, boost::mpl::int_<n>
>(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 VisitorType::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<typename Type>
void assign(const boost::shared_ptr<Type>& rspValue)
{
typedef boost::mpl::find<Typelist, boost::shared_ptr<Type>
>::type pos_t;
typedef boost::mpl::end<Typelist>::type end_t;
BOOST_STATIC_ASSERT((!boost::is_same<pos_t, end_t>::value));
m_spSelect = boost::static_pointer_cast<void>(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 boost::mpl::at<Typelist, IndexType>::type type_t;
return
rVisitor(boost::static_pointer_cast<type_t::value_type>(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,
boost::mpl::size<Typelist>::type>::type is_unrolled_t;
return apply_visitor_impl<VisitorType, IndexType>(rVisitor,
is_unrolled_t());
}
private:
boost::shared_ptr<void> m_spSelect;
size_t m_uiSelect;
};
//Helper function-template to construct the variant type
template<typename Typelist>
struct make_variant_over
{
public:
typedef CLoPtrVariant<Typelist> type;
};
//Unary visitation
template<typename Visitor, typename Visitable>
inline typename Visitor::result_type apply_visitor(const Visitor&
visitor, Visitable& visitable)
{
return visitable.apply_visitor(visitor);
}
template<typename Visitor, typename Visitable>
inline typename Visitor::result_type apply_visitor(Visitor& visitor,
Visitable& visitable)
{
return visitable.apply_visitor(visitor);
}
//Binary visitation
template <typename Visitor, typename Visitable2>
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<typename Value1>
result_type operator()(Value1& value1)
{
CBinaryUnwrap2<Visitor, Value1> unwrapper(visitor_, value1);
return apply_visitor(unwrapper, visitable2_);
}
};
template<typename Visitor, typename Value1>
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 <typename Value2>
result_type operator()(Value2& value2)
{
return visitor_(value1_, value2);
}
};
template<typename Visitor, typename Visitable1, typename Visitable2>
inline typename Visitor::result_type apply_visitor(const Visitor&
visitor, Visitable1& visitable1, Visitable2& visitable2)
{
CBinaryUnwrap1<const Visitor, Visitable2> unwrapper(visitor,
visitable2);
return apply_visitor(unwrapper, visitable1);
}
template<typename Visitor, typename Visitable1, typename Visitable2>
inline typename Visitor::result_type apply_visitor(Visitor& visitor,
Visitable1& visitable1, Visitable2& visitable2)
{
CBinaryUnwrap1<Visitor, Visitable2> unwrapper(visitor, visitable2);
return apply_visitor(unwrapper, visitable1);
}
//Base class for visitor classes
template<typename R = void>
class static_visitor
{
public:
typedef R result_type;
protected:
// for use as base class only
static_visitor() { }
~static_visitor() { }
};
template<typename Base, typename Derived>
struct is_base_of_smartptr
: boost::is_base_of<typename Base::value_type, typename
Derived::value_type>
{
};
//Convert variant types
template<typename Typelist>
class CConvertVariant
: public static_visitor<>
{
public:
CConvertVariant(CLoPtrVariant<Typelist>& rVariant)
: m_rVariant(rVariant)
{
}
template<typename Pos, typename Type>
void assign_variant(boost::shared_ptr<Type>& rValue,
boost::mpl::false_) //convertible
{
typedef boost::mpl::deref<Pos>::type type_t;
m_rVariant = boost::static_pointer_cast<type_t::value_type>(rValue);
}
template<typename Pos, typename Type>
void assign_variant(boost::shared_ptr<Type>& rValue,
boost::mpl::true_) //not convertible
{
BOOST_STATIC_ASSERT((boost::mpl::false_)); //Compiler error here
indicates that (one of) the variants bounded types is not convertible to
the target variant type
m_rVariant = rValue;
}
template<typename T>
void operator()(boost::shared_ptr<T>& rValue) //T is not const to
match the variant bounded types
{
typedef boost::mpl::find_if<Typelist,
is_base_of_smartptr<boost::mpl::_1, boost::shared_ptr<T> > >::type pos_t;
typedef boost::mpl::end<Typelist>::type end_t;
typedef boost::is_same<pos_t, end_t>::type not_convertible;
assign_variant<pos_t>(rValue, not_convertible());
}
private:
CLoPtrVariant<Typelist>& m_rVariant;
};
//Delayed visitation (std algorithm support)
template<typename VisitorType>
class CVisitDelayed
{
public:
typedef typename VisitorType::result_type result_type;
private:
VisitorType& visitor_;
public:
explicit CVisitDelayed(VisitorType& visitor)
: visitor_(visitor)
{
}
public:
//Unary
template<typename Visitable>
result_type operator()(Visitable& visitable)
{
return apply_visitor(visitor_, visitable);
}
//Binary
template<typename Visitable1, typename Visitable2>
result_type operator()(Visitable1& visitable1, Visitable2& visitable2)
{
return apply_visitor(visitor_, visitable1, visitable2);
}
};
template<typename VisitorType>
inline CVisitDelayed<VisitorType> apply_visitor(VisitorType& visitor)
{
return CVisitDelayed<VisitorType>(visitor);
}
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net