return_range¶
Definition¶
Class return_range
is a model of CallPolicies, which can be used to wrap
C++ functions that return a pointer to some array. The new call policy constructs
object, which provides a regular Python sequence interface.
Example¶
struct image_t{
...
const unsigned char* get_data() const{
return m_raw_data;
}
ssize_t get_width() const{
return m_width;
}
ssize_t get_height() const{
return m_height;
}
private:
unsigned long m_width;
unsigned long m_height;
unsigned char* m_raw_data;
};
Before introducing the whole solution, I would like to describe “return_range” interface.
return_range
class¶
template < typename TGetSize
, typename TValueType
, typename TValuePolicies=boost::python::default_call_policies >
struct return_range : boost::python::default_call_policies
{ ... };
Boost.Python call policies are stateless classes, which do not care any information about the invoked function or object. In our case we have to pass the following information:
- the array size
- the array type
- “__getitem__” call policies for the array elements
TGetSize
parameter¶
TGetSize
is a class, which is responsible to find out the size of the returned
array.
TGetSize
class must have:
default constructor
call operator with the following signature:
ssize_t operator()( boost::python::tuple args );
args
is a tuple of arguments, the function was called with.Pay attention: this operator will be invoked after the function. This call policy is not thread-safe!
For our case, the following class could be defined:
struct image_data_size_t{
ssize_t operator()( boost::python::tuple args ){
namespace bpl = boost::python;
bpl::object self = args[0];
image_t& img = bpl::extract< image_t& >( self );
return img.get_width() * img.get_height();
}
};
Passing all arguments, instead of single “self” argument gives you an ability to treat functions, where the user asked to get access to the part of the array.
struct image_t{
...
const unsigned char* get_data(ssize_t offset) const{
//check that offset represents a legal value
...
return &m_raw_data[offset];
}
...
};
The following “get size” class treats this situation:
struct image_data_size_t{
ssize_t operator()( boost::python::tuple args ){
namespace bpl = boost::python;
bpl::object self = args[0];
image_t& img = bpl::extract< image_t& >( self );
bpl::object offset_obj = args[1];
ssize_t offset = bpl::extract< ssize_t >( offset_obj );
return img.get_width() * img.get_height() - offset;
}
};
TValueType
parameter¶
TValueType
is a type of array element. In our case it is unsigned char
.
TValuePolicies
parameter¶
TValuePolicies
is a “call policy” class, which will be applied when the array
element is returned to Python. This is a call policy for “__getitem__” function.
unsigned char
is mapped to immutable type in Python, so I have to use
default_call_policies
. default_call_policies
is a default value for
TValuePolicies
parameter.
I think, now you are ready to see the whole solution:
namespace bpl = boost::python;
namespace ppc = pyplusplus::call_policies;
BOOST_PYTHON_MODULE(my_module){
bpl::class_< image_t >( "image_t" )
.def( "get_width", &image_t::get_width )
.def( "get_height", &image_t::get_height )
.def( "get_raw_data", ppc::return_range< image_size_t, unsigned char >() );
}
Py++ integration¶
The Py++ code is not that different from what you already know:
from pyplusplus import module_builder
from pyplusplus.module_builder import call_policies
image_size_code = \
"""
struct image_data_size_t{
ssize_t operator()( boost::python::tuple args ){
namespace bpl = boost::python;
bpl::object self = args[0];
image_t& img = bpl::extract< image_t& >( self );
return img.get_width() * img.get_height();
}
};
"""
mb = module_builder.module_builder_t( ... )
image = mb.class_( 'image_t' )
image.add_declaration_code( image_size_code )
get_raw_data = image.mem_fun( 'get_raw_data' )
get_raw_data.call_policies \
= call_policies.return_range( get_raw_data, "image_data_size_t" )
call_policies.return_range arguments:
- A reference to function. Py++ will extract by itself the type of the array element.
- A name of “get size” class.
- A call policies for “__getitem__” function. Py++ will analyze the array
element type. If the type is mapped to immutable type, than
default_call_policies
is used, otherwise you have to specify call policies.
Python usage code:
from my_module import *
img = image_t(...)
for p in img.get_raw_data():
print p
Dependencies¶
The new call policy depends on new indexing suite and Py++ :-).