#include "boost/python.hpp"
#include "classes.hpp"
namespace bp = boost::python;
namespace smart_pointers{
// "get_pointer" function returns pointer to the object managed by smart pointer
// class instance
template<class T>
inline T * get_pointer(smart_pointers::smart_ptr_t<T> const& p){
return p.get();
}
inline derived_t * get_pointer(derived_ptr_t const& p){
return p.get();
}
}
namespace boost{ namespace python{
using boost::get_pointer;
// "pointee" class tells Boost.Python the type of the object managed by smart
// pointer class.
// You can read more about "pointee" class here:
// http://boost.org/libs/python/doc/v2/pointee.html
template <class T>
struct pointee< smart_pointers::smart_ptr_t<T> >{
typedef T type;
};
template<>
struct pointee< derived_ptr_t >{
typedef derived_t type;
};
} }
// "get_pointer" and "pointee" are needed, in order to allow Boost.Python to
// work with user defined smart pointer
struct base_wrapper_t : base_i, bp::wrapper< base_i > {
base_wrapper_t()
: base_i(), bp::wrapper< base_i >()
{}
virtual int get_value( ) const {
bp::override func_get_value = this->get_override( "get_value" );
return func_get_value( );
}
};
struct derived_wrapper_t : derived_t, bp::wrapper< derived_t > {
derived_wrapper_t()
: derived_t(), bp::wrapper< derived_t >()
{}
derived_wrapper_t(const derived_t& d)
: derived_t(d), bp::wrapper< derived_t >()
{}
derived_wrapper_t(const derived_wrapper_t&)
: derived_t(), bp::wrapper< derived_t >()
{}
virtual int get_value() const {
if( bp::override func_get_value = this->get_override( "get_value" ) )
return func_get_value( );
else
return derived_t::get_value( );
}
int default_get_value() const {
return derived_t::get_value( );
}
};
BOOST_PYTHON_MODULE( custom_sptr ){
bp::class_< base_wrapper_t
, boost::noncopyable
, smart_pointers::smart_ptr_t< base_wrapper_t > >( "base_i" )
// -----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// HeldType of the abstract class, which is managed by custom smart pointer
// should be smart_pointers::smart_ptr_t< base_wrapper_t >.
.def( "get_value", bp::pure_virtual( &base_i::get_value ) );
// Register implicit conversion between smart pointers. Boost.Python library
// can not discover relationship between classes. You have to tell about the
// relationship to it. This will allow Boost.Python to treat right, the
// functions, which expect to get as argument smart_pointers::smart_ptr_t< base_i > class
// instance, when smart_pointers::smart_ptr_t< derived from base_i > class instance is passed.
//
// For more information about implicitly_convertible see the documentation:
// http://boost.org/libs/python/doc/v2/implicit.html .
bp::implicitly_convertible<
smart_pointers::smart_ptr_t< base_wrapper_t >
, smart_pointers::smart_ptr_t< base_i > >();
// The register_ptr_to_python functionality is explaned very well in the
// documentation:
// http://boost.org/libs/python/doc/v2/register_ptr_to_python.html .
bp::register_ptr_to_python< smart_pointers::smart_ptr_t< base_i > >();
bp::class_< derived_wrapper_t
, bp::bases< base_i >
, smart_pointers::smart_ptr_t<derived_wrapper_t> >( "derived_t" )
// -----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Pay attention on the class HeldType. It will allow us to create new classes
// in Python, which derive from the derived_t class.
.def( "get_value", &derived_t::get_value, &derived_wrapper_t::default_get_value );
// Now register all existing conversion:
bp::implicitly_convertible<
smart_pointers::smart_ptr_t< derived_wrapper_t >
, smart_pointers::smart_ptr_t< derived_t > >();
bp::implicitly_convertible<
smart_pointers::smart_ptr_t< derived_t >
, smart_pointers::smart_ptr_t< base_i > >();
bp::implicitly_convertible<
derived_ptr_t
, smart_pointers::smart_ptr_t< derived_t > >();
bp::register_ptr_to_python< derived_ptr_t >();
bp::def( "const_ref_get_value", &::const_ref_get_value );
bp::def( "ref_get_value", &::ref_get_value );
bp::def( "val_get_value", &::val_get_value );
bp::def( "create_derived", &::create_derived );
bp::def( "create_base", &::create_base );
bp::class_< numeric_t, smart_pointers::smart_ptr_t< numeric_t > >( "numeric_t" )
.def_readwrite( "value", &numeric_t::value );
bp::def( "create_numeric", &::create_numeric );
bp::def( "get_numeric_value", &::get_numeric_value );
// Work around for the public member variable, where type of the variable
// is smart pointer problem
bp::class_< shared_data::buffer_t >( "buffer_t" )
.def_readwrite( "size", &shared_data::buffer_t::size );
bp::register_ptr_to_python< smart_pointers::smart_ptr_t< shared_data::buffer_t > >();
bp::class_< shared_data::buffer_holder_t >( "buffer_holder_t" )
.def( "get_data", &shared_data::buffer_holder_t::get_data )
.def_readwrite( "data_naive", &shared_data::buffer_holder_t::data )
// If you will try to access "data_naive" you will get
// TypeError: No Python class registered for C++ class smart_pointers::smart_ptr_t<shared_data::buffer_t>
// Next lines of code contain work around
.add_property( "data"
, bp::make_getter( &shared_data::buffer_holder_t::data
, bp::return_value_policy<bp::copy_non_const_reference>() )
, bp::make_setter( &shared_data::buffer_holder_t::data ) );
}