[C++-sig] register_boost_array_from_python
Ralf W. Grosse-Kunstleve
rwgk at yahoo.com
Sat Jun 1 14:58:04 CEST 2002
> Very nice effort!
Thanks for the encouragement. Attached is the next version of the tiny
array converter, this time for boost::array<T,N> in case someone else
wants to play with it.
As shown, it does about 50000 conversions from tuples to boost::arrays
per second on our Linux PC without showing memory leaks. This includes
recovering from TypeErrors 20000 times (tuple too long; wrong element
type).
> You should use converter::callback_from_python<ElementType> instead of
> from_python<ElementType> to extract elements.
If I change #if 0 below to #if 1 I receive a segmentation fault after
a few successful passes. What am I doing wrong?
The following questions are not directly relevant to the code below,
but if you could answer them it would help foster my understanding.
> An rvalue (server side) converter must always register a function to signal
> convertibility; that's how overload resolution works. If conversion is
> going to fail after the convertible function returns true, it must be via
> an exception.
While playing around I tried throw_argument_error(). Then Python was
complaining about a "NULL result without error in PyObject_Call."
Of course, I was hoping that the overload resolution would catch
the exception and continue. Is that not an option anymore?
> > - I was hoping that
> > data->convertible = storage;
> > signals that the conversion was successful, and failed otherwise.
>
> Not quite:
> data->convertible = 0 signals failure.
> data->convertible = storage signals that the result object was constructed
> in the converter, and must be destroyed
What is the behavior if data->convertible == 0? If I just set
data->convertible = 0 flow control still arrives in my wrapped
function, but accessing the passed value causes a segmentation fault.
Does that mean I absolutely have to throw an exception if something
goes wrong in construct()?
Thanks,
Ralf
P.S.: I will now try to work this into a generic
array_from_python_list_or_tuple converter.
template <typename ElementType, std::size_t N>
struct register_boost_array_from_python
{
typedef boost::array<ElementType, N> array_type;
register_boost_array_from_python()
{
boost::python::converter::registry::insert(
&convertible,
&construct,
boost::python::type_id<array_type>());
}
static void* convertible(PyObject* obj)
{
using namespace boost::python;
tuple t = list_or_tuple_as_tuple(obj);
if (t.size() != N) return 0;
for(std::size_t i=0;i<t.size();i++) {
from_python<ElementType const&> from_py(t[i].get());
if (!from_py.convertible()) return 0;
}
return obj;
}
static void construct(
PyObject* obj, boost::python::converter::rvalue_stage1_data* data)
{
using namespace boost::python;
tuple t = list_or_tuple_as_tuple(obj);
//if (t.size() == 4) { data->convertible = 0; return; }
void* storage = ((
converter::rvalue_base_data<array_type>*)data)->storage.bytes;
new (storage) array_type();
data->convertible = storage;
array_type& result = *((array_type*)storage);
cctbx_assert(t.size() == result.size());
for(std::size_t i=0;i<result.size();i++) {
#if 0
result[i] = converter::callback_from_python<ElementType>()(t[i].get());
#else
from_python<ElementType const&> from_py(t[i].get());
result[i] = from_py(t[i].get());
#endif
}
}
private:
static boost::python::tuple list_or_tuple_as_tuple(PyObject* obj)
{
using namespace boost::python;
tuple result;
if (PyList_Check(obj)) {
result = tuple(ref(PyList_AsTuple(obj)));
}
else if (PyTuple_Check(obj)) {
result = tuple(ref(obj, ref::increment_count));
}
return result;
}
};
__________________________________________________
Do You Yahoo!?
Yahoo! - Official partner of 2002 FIFA World Cup
http://fifaworldcup.yahoo.com
More information about the Cplusplus-sig
mailing list