#ifndef MSH_UTILITY_GENERIC_PTR_H
#define MSH_UTILITY_GENERIC_PTR_H
/// <file name="generic_ptr.h">
/// <purpose>Defines generic_ptr and its generator.</purpose>
/// <author>msh</author>
/// <revisions>
/// <revision name="msh" date="2010/03/01">
/// First proposition.
/// </revision>
/// </revisions>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/seq/rest_n.hpp>
#include <boost/preprocessor/seq/elem.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/seq/seq.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/punctuation/paren.hpp>
#include <boost/preprocessor/comparison/greater.hpp>
#include <boost/preprocessor/enum_params.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/if.hpp>
#include <boost/preprocessor/empty.hpp>
#include <boost/preprocessor/comma_if.hpp>
#include <boost/shared_ptr.hpp>
//////////////////////////////////////////////////////////////////////////
// GENERAL
#define GEN_PARAMS_NONE()()
#define GEN_PARAMS(seq)(seq)
#define GEN_TYPE(type)((0)(type))
#define GEN_DEPEND_TYPE(type)((1)(type))
#define GEN_RET_NONE() ((0)(void))
#define GEN_RET_TYPE(type) ((1)(type))
#define GEN_RET_DEPEND_TYPE() ((1)(boost::any))
#define GEN_NAME(name) (name)
#define GEN_TRAILING_CONST() (const)
#define GEN_THROW_NONE() (throw())
#define GEN_THROW_OF(exc_type) (throw(exc_type))
#define GEN_METHOD_SIG(sig) (sig)
#define GEN_EMPTY_1(x) BOOST_PP_EMPTY()
#define GEN_EMPTY_2(x,y) BOOST_PP_EMPTY()
#define GEN_EMPTY_3(x,y,z) BOOST_PP_EMPTY()
#define GEN_EMPTY_4(x,y,z,t) BOOST_PP_EMPTY()
#define GEN_SELF(r,data,i,elem) elem
//////////////////////////////////////////////////////////////////////////
// CUSTOM
#define GEN_RET_COND_0
#define GEN_RET_COND_1 return
#define GEN_PARAM_TYPE_0(type) type
#define GEN_PARAM_TYPE_1(type) boost::any
#define GEN_BODY_PARAM_TYPE_0(type,param) param
#define GEN_BODY_PARAM_TYPE_1(type,param) boost::any_cast<type>(param)
//////////////////////////////////////////////////////////////////////////
// INTERFACE
#define GEN_ADD_INTERFACE_PARAM(r,data,i,seq)\
BOOST_PP_CAT(GEN_PARAM_TYPE_,BOOST_PP_SEQ_ELEM(0,seq))(BOOST_PP_SEQ_ELEM(1,seq))\
BOOST_PP_COMMA_IF(BOOST_PP_NOT_EQUAL(BOOST_PP_DEC(data),i))
#define GEN_CREATE_INTERFACE_PARAMS(seq)\
BOOST_PP_SEQ_FOR_EACH_I(GEN_ADD_INTERFACE_PARAM,BOOST_PP_SEQ_SIZE(seq),seq)
#define GEN_CREATE_INTERFACE_METHOD(r,data,seq) \
virtual BOOST_PP_SEQ_ELEM(1,BOOST_PP_SEQ_ELEM(0,seq))BOOST_PP_SEQ_ELEM(1,seq)\
BOOST_PP_LPAREN()\
BOOST_PP_IF(BOOST_PP_SEQ_SIZE(BOOST_PP_SEQ_ELEM(2,seq)),GEN_CREATE_INTERFACE_PARAMS,GEN_EMPTY_1)(BOOST_PP_SEQ_ELEM(2,seq))\
BOOST_PP_RPAREN()\
BOOST_PP_SEQ_FOR_EACH_I(GEN_SELF,~,BOOST_PP_SEQ_REST_N(3,seq))\
= 0;
#define GEN_CREATE_GENERIC_INTERFACE(seq) \
class BOOST_PP_CAT(i_generic_,BOOST_PP_SEQ_HEAD(seq))\
{\
public:\
virtual ~BOOST_PP_CAT(i_generic_,BOOST_PP_SEQ_HEAD(seq))(){}\
BOOST_PP_SEQ_FOR_EACH(GEN_CREATE_INTERFACE_METHOD,~,BOOST_PP_SEQ_TAIL(seq)) \
};
//////////////////////////////////////////////////////////////////////////
// IMPL
#define GEN_ADD_IMPL_PARAM(r,data,i,seq)\
BOOST_PP_CAT(GEN_PARAM_TYPE_,BOOST_PP_SEQ_ELEM(0,seq))(BOOST_PP_SEQ_ELEM(1,seq))\
BOOST_PP_CAT(_param_,i)BOOST_PP_COMMA_IF(BOOST_PP_NOT_EQUAL(BOOST_PP_DEC(data),i))
#define GEN_CREATE_IMPL_PARAMS(seq)\
BOOST_PP_SEQ_FOR_EACH_I(GEN_ADD_IMPL_PARAM,BOOST_PP_SEQ_SIZE(seq),seq)
#define GEN_ADD_BODY_PARAM(r,data,i,seq)\
BOOST_PP_CAT(GEN_BODY_PARAM_TYPE_,BOOST_PP_SEQ_ELEM(0,seq))(BOOST_PP_SEQ_ELEM(1,seq),BOOST_PP_CAT(_param_,i))\
BOOST_PP_COMMA_IF(BOOST_PP_NOT_EQUAL(BOOST_PP_DEC(data),i))
#define GEN_CREATE_BODY_PARAMS(seq)\
BOOST_PP_SEQ_FOR_EACH_I(GEN_ADD_BODY_PARAM,BOOST_PP_SEQ_SIZE(seq),seq)
#define GEN_CREATE_IMPL_METHOD(r,data,seq)\
BOOST_PP_SEQ_ELEM(1,BOOST_PP_SEQ_ELEM(0,seq))BOOST_PP_SEQ_ELEM(1,seq)\
BOOST_PP_LPAREN()\
GEN_CREATE_IMPL_PARAMS(BOOST_PP_SEQ_ELEM(2,seq))\
BOOST_PP_RPAREN()\
BOOST_PP_SEQ_FOR_EACH_I(GEN_SELF,~,BOOST_PP_SEQ_REST_N(3,seq))\
{\
BOOST_PP_CAT(GEN_RET_COND_,BOOST_PP_SEQ_ELEM(0,BOOST_PP_SEQ_ELEM(0,seq)))\
m_obj_sp->BOOST_PP_SEQ_ELEM(1,seq)\
BOOST_PP_LPAREN()\
GEN_CREATE_BODY_PARAMS(BOOST_PP_SEQ_ELEM(2,seq))\
BOOST_PP_RPAREN();\
}
#define GEN_CREATE_GENERIC_INTERFACE_IMPL(seq)\
template<typename T>\
class BOOST_PP_CAT(generic_,BOOST_PP_CAT(BOOST_PP_SEQ_HEAD(seq),_impl)) \
: public BOOST_PP_CAT(i_generic_,BOOST_PP_SEQ_HEAD(seq))\
{\
public: \
BOOST_PP_CAT(generic_,BOOST_PP_CAT(BOOST_PP_SEQ_HEAD(seq),_impl))(boost::shared_ptr<T> _obj_sp): m_obj_sp(_obj_sp){} \
BOOST_PP_SEQ_FOR_EACH(GEN_CREATE_IMPL_METHOD,~,BOOST_PP_SEQ_TAIL(seq)) \
private: \
boost::shared_ptr<T> m_obj_sp; \
};
namespace msh {namespace utility {
template<typename interface_t, template <typename> class handler_t>
class generic_ptr
{
typedef boost::shared_ptr<interface_t>interface_sp_t;
public:
generic_ptr(){}
template<typename obj_t>
generic_ptr(boost::shared_ptr<obj_t> _obj_sp)
{
m_obj_sp.reset(new handler_t<obj_t>(_obj_sp));
}
template<typename obj_t>
generic_ptr & operator=( boost::shared_ptr<obj_t> _obj_sp )
{
m_obj_sp.reset(new handler_t<obj_t>(_obj_sp));
return *this;
}
template<typename obj_t>
void reset(boost::shared_ptr<obj_t> _obj_sp)
{
m_obj_sp.reset(new handler_t<obj_t>(_obj_sp));
}
interface_t* operator->()const{return m_obj_sp.get();}
void swap( generic_ptr const & r )
{
m_obj_sp.swap(r.m_obj_sp);
}
private:
interface_sp_t m_obj_sp;
};
}}
#define GEN_CREATE_GENERIC_PTR(seq)\
namespace msh {namespace utility {\
typedef generic_ptr<BOOST_PP_CAT(i_generic_,BOOST_PP_SEQ_HEAD(seq))BOOST_PP_COMMA()BOOST_PP_CAT(generic_,BOOST_PP_CAT(BOOST_PP_SEQ_HEAD(seq),_impl))>\
BOOST_PP_CAT(generic_,BOOST_PP_CAT(BOOST_PP_SEQ_HEAD(seq),_ptr_t));\
}}
#define GENERIC_PTR(seq) \
namespace \
{\
GEN_CREATE_GENERIC_INTERFACE(seq)\
GEN_CREATE_GENERIC_INTERFACE_IMPL(seq)\
}\
GEN_CREATE_GENERIC_PTR(seq)
namespace msh_utils = msh::utility;
#endif // MSH_UTILITY_GENERIC_INTERFACE_H